<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 4.0.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">
  <link rel="alternate" href="/atom.xml" title="dy2903的博客" type="application/atom+xml">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/font-awesome.min.css">


<script id="hexo-configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Pisces',
    version: '7.5.0',
    exturl: false,
    sidebar: {"position":"left","display":"post","offset":12,"onmobile":false},
    copycode: {"enable":false,"show_result":false,"style":null},
    back2top: {"enable":true,"sidebar":false,"scrollpercent":false},
    bookmark: {"enable":false,"color":"#222","save":"auto"},
    fancybox: false,
    mediumzoom: false,
    lazyload: false,
    pangu: false,
    algolia: {
      appID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    },
    localsearch: {"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},
    path: '',
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    translation: {
      copy_button: 'Copy',
      copy_success: 'Copied',
      copy_failure: 'Copy failed'
    },
    sidebarPadding: 40
  };
</script>

  <meta property="og:type" content="website">
<meta property="og:title" content="dy2903的博客">
<meta property="og:url" content="https:&#x2F;&#x2F;duyang2903.gitee.io&#x2F;page&#x2F;2&#x2F;index.html">
<meta property="og:site_name" content="dy2903的博客">
<meta property="og:locale" content="en">
<meta name="twitter:card" content="summary">

<link rel="canonical" href="https://duyang2903.gitee.io/page/2/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome: true,
    isPost: false,
    isPage: false,
    isArchive: false
  };
</script>

  <title>dy2903的博客</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-meta">

    <div>
      <a href="/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">dy2903的博客</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
        <p class="site-subtitle">与肝胆人共事，从无字句读书</p>
  </div>

  <div class="site-nav-toggle">
    <div class="toggle" aria-label="Toggle navigation bar">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>
</div>


<nav class="site-nav">
  
  <ul id="menu" class="menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-fw fa-home"></i>Home</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-fw fa-archive"></i>Archives</a>

  </li>
  </ul>

</nav>
</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content">
            

  <div class="posts-expand">
        
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="en">
    <link itemprop="mainEntityOfPage" href="https://duyang2903.gitee.io/2019/11/15/%E5%A4%A7%E8%AF%9D%E5%AD%98%E5%82%A8%EF%BC%8C%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%8814%E7%AB%A0%EF%BC%89%EF%BC%8C-%E8%99%9A%E6%8B%9F%E5%8C%96/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="dy2903">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="dy2903的博客">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          
            <a href="/2019/11/15/%E5%A4%A7%E8%AF%9D%E5%AD%98%E5%82%A8%EF%BC%8C%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%8814%E7%AB%A0%EF%BC%89%EF%BC%8C-%E8%99%9A%E6%8B%9F%E5%8C%96/" class="post-title-link" itemprop="url">大话存储，学习笔记（14章），-虚拟化</a>
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">Posted on</span>

              <time title="Created: 2019-11-15 10:48:24" itemprop="dateCreated datePublished" datetime="2019-11-15T10:48:24+08:00">2019-11-15</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">Edited on</span>
                <time title="Modified: 2019-11-13 21:27:13" itemprop="dateModified" datetime="2019-11-13T21:27:13+08:00">2019-11-13</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h2 id="操作系统对硬件的虚拟化"><a href="#操作系统对硬件的虚拟化" class="headerlink" title="操作系统对硬件的虚拟化"></a>操作系统对硬件的虚拟化</h2><blockquote>
<p><code>操作系统</code>：就是为其他<strong>程序</strong>提供编写和运行环境的<strong>程序</strong>。</p>
</blockquote>
<p>由程序来运行程序，而不是程序自己来运行，<strong>这是操作系统提供的虚拟化的表现</strong>。</p>
<p>加电之后，首先运行OS，随时可以载入其他程序执行。执行完以后切换回OS本身。</p>
<p>但是每次还是要等待这个程序执行完毕，才能接着载入下个程序执行。任何中断事件，都会中断正在运行的程序。</p>
<p>程序执行完毕，会将CPU归还给OS。从而继续OS本身的运行。这种操作系统就是<strong>单任务操作系统</strong>，典型代表就是DOS。</p>
<p>而批处理就是操作系统将多个程序一个一个的排列起来。省去了人为载入的过程。所以批处理操作系统相对单任务来说又进了一步，但是本质仍然是一个程序独占资源。</p>
<p>再后来操作系统针对系统时钟中断开发了中断服务程序，也就是<strong>多任务OS中的调度程序</strong>。</p>
<p>中断来临，CPU根据中断向量表的内容，指向调度程序所在的内存地址入口，执行调度程序的代码。<br>调度程序将CPU的执行跳转到各个应用程序所在的内存地址入口。</p>
<p>从微观上看，每个应用程序独占CPU，但是时间非常小10ms，从宏观上看就是同时执行多个任务。</p>
<p>多任务操作系统的关键就是有<strong>多任务调度程序。</strong><br><img src="http://upload-images.jianshu.io/upload_images/1323506-a91b1cc253c1c8a4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h2 id="虚拟化的好处"><a href="#虚拟化的好处" class="headerlink" title="虚拟化的好处"></a>虚拟化的好处</h2><p>虚拟化的好处是，<strong>将下层复杂的逻辑转换为上层简单的逻辑</strong>，方便人类读懂。</p>
<p>其实整个计算机技术就是抽象、封装、虚拟、映射的过程。就连CPU也在想办法把功能封装到CPU的逻辑电路里面，从而出现了更多的指令集。1.6GHz的酷睿双核CPU性能比主频3GHz的奔腾4代CPU更高。</p>
<h2 id="计算机存储子系统的虚拟化"><a href="#计算机存储子系统的虚拟化" class="headerlink" title="计算机存储子系统的虚拟化"></a>计算机存储子系统的虚拟化</h2><p>存储子系统主要分为：</p>
<ul>
<li>磁盘</li>
<li>磁盘控制器</li>
<li>存储网络</li>
<li>磁盘阵列</li>
<li>卷管理层</li>
<li>目录虚拟层</li>
<li>文件系统虚拟层</li>
</ul>
<p>下面将介绍这些子系统如何进行抽象虚拟的。</p>
<h3 id="磁盘控制器的虚拟化"><a href="#磁盘控制器的虚拟化" class="headerlink" title="磁盘控制器的虚拟化"></a>磁盘控制器的虚拟化</h3><p><strong>控制器的工作</strong>就是根据驱动程序发来的磁盘读写信息，向磁盘发送<strong>SCSI指令</strong>和数据。</p>
<p>所以磁盘控制器完全可以对<strong>驱动程序</strong>隐藏下挂的物理磁盘。而虚拟出一个或者多个虚拟磁盘。RAID就是典型代表。控制器将物理磁盘组成RAID Group，然后在RG的基础上虚拟出多个LUN，通告给主机驱动。</p>
<h3 id="存储网络的虚拟化"><a href="#存储网络的虚拟化" class="headerlink" title="存储网络的虚拟化"></a>存储网络的虚拟化</h3><p>在交换式SAN中，任何节点都是通过交换设备来进行通信的，如果在交换节点上做些手脚，就可以达到虚拟化的效果。</p>
<p>我们可以在交换机上嵌入SCSI协议感知模块。，SCSI发起设备向目标设备传输的数据，经过交换机，会主动复制对应的帧到另一个节点的LUN上，形成镜像。若一个节点故障，则会将数据<strong>重定向</strong>到镜像的LUN上。</p>
<p>还可以将某些N节点的LUN合并成<strong>池</strong>，然后动态的从这个池中分出虚拟LUN</p>
<h3 id="磁盘阵列的虚拟化"><a href="#磁盘阵列的虚拟化" class="headerlink" title="磁盘阵列的虚拟化"></a>磁盘阵列的虚拟化</h3><p>磁盘阵列本来就是一个小计算机系统，是对存储子系统的抽象虚拟化最佳表现。</p>
<p>何为磁盘阵列，指的是将大量磁盘进行组织管理，抽象虚拟成<strong>逻辑磁盘</strong>。通过和主机适配器通信，呈现给主机。</p>
<p>盘阵控制器的角色都是不直接参与连接每块磁盘，而是利用后端适配器来管理下挂的磁盘</p>
<blockquote>
<p>适配器就是中心控制器驱动的二级磁盘控制器。作为中心CPU的IO适配器，直接控制和管理物理磁盘，然后由中心控制器统一实现RAID、卷管理等功能。</p>
</blockquote>
<p>后端适配器与中心控制器CPU之间通过PCIX总线等连接。</p>
<p>中心控制器不但可以实现最基本的RAID功能，还可以实现<strong>LUN镜像、快照、远程复制、CDP数据保护、LUN再分配等。</strong></p>
<h3 id="卷管理层"><a href="#卷管理层" class="headerlink" title="卷管理层"></a>卷管理层</h3><p>运行在<strong>应用主机</strong>上的功能模块，对底层的物理磁盘或者LUN搜集再分配。</p>
<p>对盘阵控制器虚拟化之后的LUN再<strong>虚拟化</strong>，</p>
<ul>
<li><p>比如进行镜像处理，</p>
</li>
<li><p>或者对其中的多个LUN做成软RAID 。</p>
</li>
<li><p>再或者将所有的LUN合并形成资源池。</p>
</li>
</ul>
<p>然后掰成多个<strong>卷</strong>。</p>
<h3 id="文件系统"><a href="#文件系统" class="headerlink" title="文件系统"></a>文件系统</h3><p>SAN存储解决的是怎么记录的问题，文件系统解决的是怎么组织磁盘的数据</p>
<blockquote>
<p>需要在相应的地方做标记，通过一个链表一次一次指引找出完整的数据。</p>
</blockquote>
<p>把链表单独做成一个记录，放在固定的位置，可以通过表找出一条数据在磁盘上的完整分布。利用这种思想做出来的文件系统，比如FAT文件系统，把每个完整数据称为<strong>文件</strong>。</p>
<blockquote>
<p>文件分配表：FAT , File Allocate Table文件可以在磁盘不连续的存放，由单独数据结构来描述文件在磁盘的分布，</p>
</blockquote>
<blockquote>
<p>NTFS：给出文件在磁盘上的具体扇区，利用“开始——结束”这样的结构来描述文件的分布情况。</p>
</blockquote>
<p>文件系统将磁盘抽象成了文件柜，同一份文件放在柜子的不同抽屉，利用<code>元数据</code> 来记录“文件——对应抽屉” 的分布情况。</p>
<blockquote>
<p>描述其他文件分布情况及属性的文件，<code>元文件Metadata</code></p>
</blockquote>
<p>文件系统是对磁盘块的虚拟、抽象、组织和管理。只需要访问文件，就等于访问了扇区。</p>
<h3 id="目录虚拟层"><a href="#目录虚拟层" class="headerlink" title="目录虚拟层"></a>目录虚拟层</h3><p>操作系统中有一个虚拟目录结构，在linux中叫VFS。–</p>
<p>虚拟文件系统，也就是说文件系统的目录不是真实的，任何的文件系统可以挂在目录下。成为虚拟目录的子目录，可以增强灵活性。</p>
<p>其次，OS外部设备虚拟成一个虚拟文件，比如卷。/dev/hda</p>
<blockquote>
<p>磁盘——控制器——存储网络——总线适配器——卷管理层——文件系统——虚拟目录层和最终应用层</p>
</blockquote>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-222c51bc71ed8292.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h2 id="带内虚拟化和带虚拟化"><a href="#带内虚拟化和带虚拟化" class="headerlink" title="带内虚拟化和带虚拟化"></a>带内虚拟化和带虚拟化</h2><ul>
<li><p>带内 InBand ：控制指令和数据包走同一路线，所谓<strong>控制指令</strong>指的是控制数据流向的数据，如IP路由协议产生的数据包，它也是利用实际数据线路进行传输。</p>
</li>
<li><p>带外 OutBand：控制指令走单独的路线。</p>
</li>
</ul>
<p>带外和带内虚拟化：</p>
<ul>
<li><p>带内虚拟化：进行虚拟化的设备直接横在发起者和目标路径之间，也就是串在同一路径上，作为一个“泵”</p>
</li>
<li><p>带外虚拟化：旁路，用这条路径来走控制信号，而实际数据还是由发起者直接走向目标。发起者必须先咨询旁路的虚拟化设备，经过提示之后，才根据虚拟化设备的指示直接向目标请求数据</p>
</li>
</ul>
<h2 id="硬网络与软网络"><a href="#硬网络与软网络" class="headerlink" title="硬网络与软网络"></a>硬网络与软网络</h2><h3 id="硬网络"><a href="#硬网络" class="headerlink" title="硬网络"></a>硬网络</h3><p>硬件网络设备其功能还是靠软件来实现的，特别是路由设备，本质是一台Server，上面运行着处理数据包的程序。</p>
<p>所以硬件<strong>网络环境</strong>实际上是用一部分PC充当网络硬件设备，其他PC利用网络设备的PC实现通信</p>
<h3 id="软件网络程序"><a href="#软件网络程序" class="headerlink" title="软件网络程序"></a>软件网络程序</h3><p>message queue和Message Broker在硬件网络设备 的基础上，模拟出一个纯软件的网络转发引擎。</p>
<blockquote>
<p>MQ：消息转发器。客户端通过TCP/IP与之相连，将消息转发到这个转发器上，然后根据策略将消息转发到其他客户端上。类似于交换机，不过MQ的链路层由TCP/IP来充当</p>
</blockquote>
<blockquote>
<p>MB：应用逻辑转发引擎。应用层次的转发，类似邮件服务器。只不过可转发各种格式的数据包。</p>
</blockquote>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-171f4c7221a33025.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h2 id="多虚一"><a href="#多虚一" class="headerlink" title="多虚一"></a>多虚一</h2><h2 id="HPC"><a href="#HPC" class="headerlink" title="HPC"></a>HPC</h2><p>HPC主要分为两类：</p>
<ul>
<li><p>CPU密集运算：专门用来计算数据，称为计算节点</p>
</li>
<li><p>IO密集运算：专门用来存储计算过程中所需要提取或者存放的数据，称为存储节点</p>
</li>
</ul>
<p>计算节点看做CPU和内存，存储节点看做硬盘。对独立的PC，CPU内存与硬盘的连接为高速IO总线，如PCIe</p>
<p>但是对HPC ，有些利用Infiniband有些利用以太网。前者一般适用于IO密集运算，后者用于CPU密集运算。</p>
<h2 id="Web-APP-db"><a href="#Web-APP-db" class="headerlink" title="Web + APP + db"></a>Web + APP + db</h2><p>客户端通过Web服务器获得网页，应用逻辑由APP服务器处理。最后通过Web服务器进行展现。</p>
<p>可以把Web看做显示终端，APP看做CPU和内存，将DB看做硬盘</p>
<h2 id="一虚多"><a href="#一虚多" class="headerlink" title="一虚多"></a>一虚多</h2><blockquote>
<p>计算虚拟化：模拟硬件系统，将程序对这个硬件系统CPU发送的指令经过处理之后，加以虚拟传到物理CPU上。比如Vmware的ESX </p>
</blockquote>
<h2 id="用磁盘阵列来虚拟磁带库"><a href="#用磁盘阵列来虚拟磁带库" class="headerlink" title="用磁盘阵列来虚拟磁带库"></a>用磁盘阵列来虚拟磁带库</h2><blockquote>
<p>VTL,Virtual Tape Lib </p>
</blockquote>
<p>要提高磁带库的速度，只能多个驱动器同时工作，成本高。</p>
<p><strong>VTL使用磁盘来存储数据而不是磁带，虚拟出机械手、磁带驱动器、磁带</strong></p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

        
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="en">
    <link itemprop="mainEntityOfPage" href="https://duyang2903.gitee.io/2019/11/15/%E5%A4%A7%E8%AF%9D%E5%AD%98%E5%82%A8%EF%BC%8C%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%8815%E7%AB%A0%EF%BC%89%EF%BC%8C%E9%9B%86%E7%BE%A4%E6%A6%82%E8%AE%BA/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="dy2903">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="dy2903的博客">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          
            <a href="/2019/11/15/%E5%A4%A7%E8%AF%9D%E5%AD%98%E5%82%A8%EF%BC%8C%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%8815%E7%AB%A0%EF%BC%89%EF%BC%8C%E9%9B%86%E7%BE%A4%E6%A6%82%E8%AE%BA/" class="post-title-link" itemprop="url">大话存储，学习笔记（15章），集群概论</a>
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">Posted on</span>

              <time title="Created: 2019-11-15 10:48:24" itemprop="dateCreated datePublished" datetime="2019-11-15T10:48:24+08:00">2019-11-15</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">Edited on</span>
                <time title="Modified: 2019-11-13 21:27:13" itemprop="dateModified" datetime="2019-11-13T21:27:13+08:00">2019-11-13</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>随着应用程序对服务器、存储系统的系统要求越来越高，单台设备有时已经无法满足需求了，此时我们有两种方法可以解决：</p>
<ul>
<li><p>使用性能更高的机器，但是成本以及维护成本非常高，而且不见得适合所有的应用。</p>
</li>
<li><p>多台设备联合起来对外提供服务，这就是集群。</p>
</li>
</ul>
<p>主机可以形成集群，存储设备也可以形成集群。目前中高端存储设备自身就有双控制器。</p>
<p>一些NAS设备可以在多台独立设备之间形成集群，并实现单一命名空间，<strong>即用户访问目录路径就像访问一台机器一样。</strong>屏蔽了后端访问的过程，实际上，可能是由集群中不同的节点来提供服务的。</p>
<h1 id="集群概述"><a href="#集群概述" class="headerlink" title="集群概述"></a>集群概述</h1><p>上面讲到了为什么要用<strong>集群</strong>，首先用多个节点来代替一个节点完成任务，处理能力可以得到提高，其实还可以获得<strong>高可用性</strong>，即一个节点发生故障，另外的节点可以接替故障节点。</p>
<p>我们可以把集群分为三种：</p>
<ul>
<li><p>高可用集群</p>
<p>  在HA集群中，节点分为<strong>活动节点和备份节点</strong>，当活动节点故障了以后，备份节点立即接替任务。</p>
<p>  那怎么实现<strong>切换的</strong>呢？HA集群的实现是基于<strong>资源切换</strong>。资源指的是备份节点要接管的所有东西，比如IP地址、磁盘卷、上下文等。</p>
<p>  那怎么知道需要主节点挂了呢？需要依靠<strong>操作系统上安装的HA软件。</strong>它可以监控对方<strong>节点状态</strong>，一旦发现故障，则强行将资源占有。</p>
</li>
<li><p>负载均衡集群</p>
<p>  负载均衡节点中，所有节点都参与工作。每个节点的地位相同，但是工作量怎么分配呢？可以有两种方式：</p>
<ul>
<li><p>由单独的节点来分配运算量</p>
</li>
<li><p>也可以由节点通过网络通信来协商。</p>
</li>
</ul>
</li>
<li><p>高性能集群</p>
<p>  又称科学计算集群，其实与负载均衡集群本质上是一样的 ，不过主要用于科学计算而已，所以这种集群主要面向与CPU消耗型的应用。</p>
<p>  如何把任务平均分配到每个CPU核心上呢？如果在一台计算机上则非常简单，操作系统会自动将<strong>多个线程平摊到多个CPU核心上</strong>。</p>
<p>  但是在集群里面，则可以通过网络来进行协商。为了方便编程，还开发出很多API，可以屏蔽很多编程复杂度。所以节点收到任务数据之后，再由节点操作系统自行将任务数据分派到多个CPU核心上。</p>
</li>
</ul>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-65a5b040487fbb06.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h2 id="系统路径上的集群各论"><a href="#系统路径上的集群各论" class="headerlink" title="系统路径上的集群各论"></a>系统路径上的集群各论</h2><p>集群可以在系统路上的任何点实现。比如CPU、内存、显卡等硬件可以形成集群，软件上，应用程序、文件系统、卷管理系统也可以形成集群。</p>
<p>什么时候需要集群呢？</p>
<ul>
<li><p>当需要系统高可用的时候，也就是某处故障不会影响系统的可用，可选择使用高可用性集群</p>
</li>
<li><p>当单个系统的处理能力不能满足性能要求的时候，可使用负载均衡集群</p>
</li>
<li><p>当需要运算的数据量很大的时候，运算周期很长的时候，可使用高性能集群。</p>
</li>
</ul>
<p>下面我们一一谈一下硬件层面和软件层面的集群。</p>
<h3 id="硬件层面的集群"><a href="#硬件层面的集群" class="headerlink" title="硬件层面的集群"></a>硬件层面的集群</h3><p><img src="http://upload-images.jianshu.io/upload_images/1323506-14aeefaaa2da8d53.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<ul>
<li><p>CPU集群：体现在多CPU的计算机系统，比如对称多处理系统，多个CPU共享物理内存相互协作。</p>
</li>
<li><p>内存集群：多条内存组成更大的容量空间。比如通过<strong>双通道</strong>提高性能（相当于条带化RAID0）</p>
</li>
<li><p>以太网卡集群：将多块以太网卡绑定在一起，向上提供<strong>虚拟网卡</strong>，底层则可以通过ARP轮询负载均衡，或者HA方式的多路径访问。</p>
</li>
<li><p>以太网集群：多台设备协作转发，实现了负载均衡和HA，体现在路由器和以太网交换机上。</p>
</li>
<li><p>显卡集群：将插在总线上的多块显卡连接起来，实现对大型3D数据渲染负载均衡，性能可以得到很大的提升。</p>
</li>
<li><p>FC卡的集群：通过与主机上的<strong>多路径软件</strong>配合，多块FC卡之间可以实现流量的负载均衡和HA，或者通过FC网络中的ISL链路负载均衡、HA方式实现流量分摊</p>
</li>
<li><p>FC网络设备的集群：一般来说FC网络设备没有向以太网交换机那样实现了负载均衡和HA 。</p>
</li>
<li><p>控制器集群：几乎中高端磁盘阵列的控制器都是双控的，可以是HA关系，或者是负载均衡关系。</p>
</li>
<li><p>磁盘集群:典型的集群是RAID系统，</p>
</li>
</ul>
<h3 id="软件层面的集群"><a href="#软件层面的集群" class="headerlink" title="软件层面的集群"></a>软件层面的集群</h3><ul>
<li><p>应用程序的集群：一个应用程序可以同时启动多个实例（进程），共同完成工作 。不同实例可以运行在同一机器上，也可运行在不同的机器上，通过网络交互信息。</p>
</li>
<li><p>文件系统的集群：文件系统的集群是一个比较独立的课题。可以实现集群功能的文件系统叫<strong>集群文件系统</strong>，比如NFS、CIFS等网络文件系统，就是最简单的集群文件系统。</p>
<p>  集群文件系统主要为了解决：容量、性能、共享</p>
<ul>
<li><p>解决容量问题：比如说<strong>分布式文件系统</strong>，文件的存储其实是分散在各个节点上的，但是对外呈现统一的<strong>命名空间，也即目录</strong>。</p>
<p>也就是说分布式文件系统将每个节点的可用空间进行虚拟的整合，形成虚拟目录，对外屏蔽细节，对外根据多种策略来判断数据流向，将数据写入实际的空间里面。</p>
</li>
<li><p>解决性能问题。</p>
<p>同样的，可以使用多个节点来获得高性能。集群文件系统使得每个节点不必连接昂贵的磁盘阵列，就可以获得较高的文件IO性能。</p>
<p>在分布式文件系统的<strong>虚拟整合目录</strong>之上，采用了类似条带RAID 0的方式，依据负载均衡策略，将每次IO写入的数据，负载分担到所有节点上，节点获得的性能越多提升就越大。</p>
<p>但是实际上，集群文件系统实施起来不那么容易，需要经过长时间的调优。</p>
</li>
<li><p>解决共享访问的问题。</p>
<p>这是集群文件系统要解决的<strong>最重要的问题</strong>，也就是多节点共同访问相同目录和相同文件时一致性的问题。</p>
<p>集群文件系统需要考虑多个节点同时读写相同文件，保证所有节点都能读到一致性的数据，并利用分布式锁机制保证允许的性能下，节点之间不会写冲突。</p>
<p>常用的集群文件系统有PVFS,GFS,DFS，Lustre等</p>
</li>
</ul>
</li>
<li><p>卷管理系统集群</p>
<p>  本机的卷和本机和远程的卷进行镜像等协同操作，形成集群。<br><img src="http://upload-images.jianshu.io/upload_images/1323506-7e1a02a6d51307cf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
</li>
</ul>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

        
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="en">
    <link itemprop="mainEntityOfPage" href="https://duyang2903.gitee.io/2019/11/15/%E5%A4%A7%E8%AF%9D%E5%AD%98%E5%82%A8%EF%BC%8C%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%884%EF%BC%8C5%E7%AB%A0%EF%BC%89%EF%BC%8CRAID/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="dy2903">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="dy2903的博客">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          
            <a href="/2019/11/15/%E5%A4%A7%E8%AF%9D%E5%AD%98%E5%82%A8%EF%BC%8C%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%884%EF%BC%8C5%E7%AB%A0%EF%BC%89%EF%BC%8CRAID/" class="post-title-link" itemprop="url">大话存储，学习笔记（4，5章），RAID</a>
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">Posted on</span>

              <time title="Created: 2019-11-15 10:48:24" itemprop="dateCreated datePublished" datetime="2019-11-15T10:48:24+08:00">2019-11-15</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">Edited on</span>
                <time title="Modified: 2019-11-13 21:27:13" itemprop="dateModified" datetime="2019-11-13T21:27:13+08:00">2019-11-13</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="RAID"><a href="#RAID" class="headerlink" title="RAID"></a>RAID</h1><p>上一章介绍了磁盘的基本原理，我们知道一块磁盘的容量和速度是有限的，对于一些应用来说，可能需要几个TB的大小的来存放数据，我们必须要制造更大单盘容量的磁盘吗？实际上，可以使用多块磁盘并行起来解决这个问题，这就是RAID技术。</p>
<blockquote>
<p><code>RAID</code>:独立的磁盘组成具有冗余特性的阵列。Redundant Array of Independent Disks</p>
</blockquote>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-cb2e95dc2649ba2f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"><br>n</p>
<h2 id="七种RAID"><a href="#七种RAID" class="headerlink" title="七种RAID"></a>七种RAID</h2><h3 id="RAID-0"><a href="#RAID-0" class="headerlink" title="RAID 0"></a>RAID 0</h3><p>实现RAID 0 有两种方式，<strong>一种是非条带化的模式，一种是条带化的模式。</strong></p>
<p>对于<strong>非条带化的</strong>模式：</p>
<p>RAID 0 ： 一块磁盘写满了，就往另一块上写， 一次IO只用到一块磁盘，对整个系统来说容量增大了。</p>
<p>因为写满一块物理盘以后再写另一块盘<strong>。对写IO没有任何优化，但是对读IO能提高一定的并发IO读几率。</strong></p>
<p>我们希望可以这样，同时向<strong>两块磁盘</strong>进行写。我们可以把要写的IO块进行编号，1、2、3……100等，然后在$t_1$时刻，磁盘A和磁盘B同时写入1、3两块，然后$t_2$时刻，同时写入2、4块，依次类推。</p>
<p>这样就可以实现<strong>并发写IO</strong>呢。接下来就是如何来进行块的划分的问题了。</p>
<p>其实磁盘已经经过低级格式化了，也就是划分为若干的扇区，但是扇区只有512B大小，这么小的粒度太消耗性能。所以我们要重新划分磁盘，而且又不能抛弃原有的扇区。</p>
<p>最直接的想法就是若干个<strong>扇区</strong>组成一个<code>Data block</code>，比如由4个扇区组成一个<strong>块(block)</strong></p>
<ul>
<li><code>data Block</code>：N倍个扇区大小的容量，Block只有在一个Segment中是物理连续的，逻辑连续就需要跨物理磁盘。</li>
</ul>
<p>下图是引入了分割思想以后的硬盘，</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-e245896c7456ee63.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<ul>
<li>不同磁盘的相同偏移处的块组成成了Stripe，也就是<strong>条带，Stripee</strong></li>
<li><code>Segment</code>：一个Stripee所占用的<strong>单块</strong>磁盘上的区域。</li>
</ul>
<p>那么条带深度和条带长度指的就是</p>
<ul>
<li>每个Segment包含的块或者扇区的数量称为<code>条带深度</code></li>
<li><code>条带长度</code>：一Stripee横跨过的<strong>扇区</strong>或者块的个数或者字节容量。</li>
</ul>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-7d4d32249be925f3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>总结</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-a9f75bd4cb3954f1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>这就是所谓的<strong>条带化</strong>，它是对磁盘<strong>逻辑上的划分</strong>，相当于在磁盘上加了一个<strong>中间层</strong>而已</p>
<p>这样对于一个大块的数据，<strong>可以以条带为单位进行写入，也就是数据被分为了多块写入了4块硬盘。</strong>而不是向之前一样顺序的写入一个硬盘里面</p>
<p>RAID 0要提升性能，条带要做得越小越好。因为若是条带深度容量大于写入的数据的长度，这段数据将会落到同一个segment中，相当于本次IO只能从一块硬盘中读取。</p>
<p><strong>但是条带太小，并发IO几率降低。</strong>因为如果条带太小，每次IO一定会占用大部分物理盘，队列中的IO只能等待IO结束后才使用物理盘。</p>
<p>总之，参与RAID0 的物理盘会组成<strong>一个逻辑上连续，物理上也连续的虚拟磁盘</strong>。控制器对虚拟磁盘发出的指令，被RAID控制器转换为真实磁盘IO，再返回主机磁盘控制器，经过控制器在cache中的组合，再提交给主机控制器。</p>
<p>RAID 0有非常明显的缺点，没有任何的备份，所以任何一块硬盘损坏均会造成数据丢失。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-ffd7c466169b28f7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h3 id="RAID-1"><a href="#RAID-1" class="headerlink" title="RAID 1"></a>RAID 1</h3><p>RAID 0 最大的<strong>缺点</strong>是没有备份盘。RAID 1 进行了改正。他采用了一块用于正常使用，另一块作为<strong>影子盘</strong>存在。</p>
<p>也就是写数据的时候，会写两份。所以写的时候的速度并不快，而且可用容量实际上就只有一块盘，空间浪费很严重。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-c4a87ddbf196f57a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h3 id="RAID-2"><a href="#RAID-2" class="headerlink" title="RAID 2"></a>RAID 2</h3><p>RAID 0 速度快，但是没有备份，RAID 1 有备份，但是可用容量太少。</p>
<p>RAID 2 的改进在于引入了<code>校验盘</code>的概念。当数据损坏的时候，可以根据校验盘的数字，恢复原来磁盘上的数字。</p>
<p>RAID 2采用“汉明码”来进行校验，这种纠错技术算法比较复杂，而且需要加入大量的校验位，比如4位数据编码，会加入3位校验位。</p>
<p>同时数据存储的时候，<strong>会把每个IO下的数据以位为单位强行打散在每个磁盘。</strong></p>
<p>磁盘最小的IO单位是512B，如何写入1bit？上层IO可以先经过文件系统，然后通过磁盘控制器驱动向磁盘发出IO。最终IO大小都是N倍的扇区。即使只要几个字节，也需要读出整个扇区</p>
<p>所以<strong>每次必须所有联动起来一次进行存储</strong>，如果各磁盘的主轴没有同步，则先读出数据的硬盘需要等待。所以开销也比较大。</p>
<p>正因为此，目前RAID2已经不怎么使用了。<br><img src="http://upload-images.jianshu.io/upload_images/1323506-6a6f430e3be3047f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h3 id="RAID-3"><a href="#RAID-3" class="headerlink" title="RAID 3"></a>RAID 3</h3><p>RAID 3引入了一种新的校验算法，可以将数据盘中的每个位做<strong>XOR</strong>运算，然后将结果写入到校验盘的对应位置。任何一个扇区损坏，可以通过剩余的位和校验位一起进行XOR运算来获得丢失的位。</p>
<p>同时RAID 3 把条带长度设置为4K字节，因为一般文件系统刚好是4KB一个块，所以如果用4块数据盘，条带深度为1KB，也就是2个扇区。这样，可以保证连续写的时候，<strong>以条带为单位写入，提高并行度</strong>。</p>
<p>所以RAID 2和RAID 3的每次IO都会牵动所有磁盘并行读写，每次只能做一个IO，不适合多IO并发的情况。</p>
<p>也说RAID 2和RAID 3适合IO块大的情况</p>
<blockquote>
<p>一般来说，RAID 3 的条带长度= 文件系统的大小，就不会产生条带不对齐的现象。减少碎片。</p>
</blockquote>
<p><strong>关于RAID 3的校验盘有没有瓶颈的问题</strong></p>
<p>若一个逻辑块是4KB，4+1块盘，文件系统下发一个IO至少是以一个逻辑块为单位的。所以文件系统下发一次IO，不管多大都是跨越了所有数据盘的。</p>
<ol>
<li>连续<ol>
<li>连续读：寻道时间忽略，IOPS受限于传输时间，因为RAID 3 是把一个IO分散到N个数据盘上，即传输时间是单盘的1/N，<strong>即持续读的性能是单盘的N倍。</strong></li>
<li>持续写：分担到N个盘，也是单盘的1/N。因为每次IO写，物理磁盘上的所有分块都需要更新，包括校验块，<strong>就没有瓶颈和热点的区别。</strong></li>
</ol>
</li>
<li>随机<ol>
<li>随机读写：多个盘同时换道，所以性能相对于单盘没有提升。而且有的磁盘不是严格主轴同步的，会拖累。</li>
<li>并发IO：一次IO必定会占用所有的盘，其他的盘必须等待，<strong>所以根本不能并发IO</strong>。</li>
</ol>
</li>
</ol>
<p><strong>总结起来就是RAID 3适合于连续大块的读和写，不适合于随机IO和并发IO。</strong></p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-7c286f7f8722074b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h3 id="RAID-4"><a href="#RAID-4" class="headerlink" title="RAID 4"></a>RAID 4</h3><ul>
<li>RAID 0属于激进派，为了速度，根本不要备份。</li>
<li>RAID 1属于保守派，需要浪费一个镜像的容量。</li>
<li>RAID 2和RAID 3 属于中庸派。</li>
</ul>
<p>RAID 2和RAID 3已经解决了校验盘的问题，避免了一块盘损坏数据全丢失的问题。但是对于无法得到<strong>并发IO</strong>的问题还没解决。</p>
<p>RAID 2和RAID 3的思想是让所有数据盘都参与起来。对于随机小块读写，每秒产生的IO数目很大，但是每个IO的请求数据长度却很短，如果所有磁盘同一时刻都在处理一个IO，得不偿失。不如让这个IO直接写入一块磁盘，其他的做其他的IO。</p>
<p>方法有：</p>
<ul>
<li>可以增加条带深度，一个IO比条带深度小，所以可以完全被一个磁盘所处理。直接写入了一块磁盘的Segment中。</li>
<li>增大数据的随机分布性，不要连续在一块磁盘分布，要和其他IO所用的磁盘不一样。</li>
</ul>
<p>所以 RAID 4 的改进是<strong>增加了条带深度</strong>，RAID 4相对于RAID 3 性能几乎没有提升。但是至少让它可以进行<strong>并发IO</strong></p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-f0abce0cc5e638b2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h3 id="RAID-5"><a href="#RAID-5" class="headerlink" title="RAID 5"></a>RAID 5</h3><p>RAID 4相对于RAID 3 性能几乎没有提升。而且因为每个IO必定会占用校验盘， <strong>所以校验盘成为了瓶颈，而且是热点盘，容易坏。</strong></p>
<p>这样看来RAID 4其实有些不伦不类。</p>
<p>RAID 4的关键错误在于忽略了校验盘，每个IO不管怎么样都会读写校验盘的。</p>
<p>RAID 5的改进在于将校验盘<strong>把校验盘分割开，依附于数据盘。</strong>把条带做得很大，保证每次IO不会占满整个条带。</p>
<p>2块盘的RAID 5系统，对于写操作来说不能并发IO，因为访问一块盘的时候，校验信息一定在另一块盘中。同理，3块盘也不能</p>
<p>所以最低可以<strong>并发IO的RAID 5 需要4块盘</strong>，此时最多可以<strong>并发两个IO</strong>，并发的几率是0.0322。</p>
<p><strong>RAID 5 磁盘数量越多，并发的几率越大。</strong></p>
<p>[图片上传失败…(image-125f7b-1517815816644)]</p>
<p><strong>RAID 5与RAID 0相比</strong></p>
<p>RAID 5 是继RAID 0 , RAID 1以后又一个可以实现并发IO的阵式，但是比RAID 1更划算，比RAID 0更安全。</p>
<ul>
<li>容量方面：随着磁盘数增加，RAID5浪费的是N分之一，而RAID永远是二分之一。</li>
<li>性能方便：RAID 5和RAID 0都是使用条带来提升性能，但是RAID 6又克服了RAID 0的无保护。</li>
</ul>
<p><strong>RAID 5与RAID 3相比</strong></p>
<p>RAID 5的连续读写不如RAID 3，因为RAID 3 的条带深度很小，每次IO可以牵动所有的磁盘为之服务。</p>
<p>RAID 5 每次IO一般只使用一块数据盘，先放满一个Segment，再去下一个磁盘的Segment存放，块编号是横向进行。</p>
<p>所以<strong>RAID 3在IO SIZE大的时候高性能，RAID 5在随机IOPS大时有高性能。</strong></p>
<h4 id="RAID-5的缺点"><a href="#RAID-5的缺点" class="headerlink" title="RAID 5的缺点"></a>RAID 5的缺点</h4><p>RAID 5的缺点是<code>写惩罚</code>：写性能差，因为每写一扇区就要产生其校验扇区，一并写入校验盘。</p>
<p>新数据过来，控制器立即读待更新扇区的数据，然后读此条带的校验数据根据公式<code>新数据的校验数据 = （老数据 EOR 新数据） EOR  老校验数据</code> 得到新校验数据，然后写到磁盘中。</p>
<p>所以每次写入都需要更新校验盘。浪费3个其他动作，也就是读老数据，读老校验数据，然后写新数据和校验数据，浪费了除了“写新数据”之外的操作。</p>
<blockquote>
<p>总结：随机并发IO和写性能二者只能取其一。</p>
</blockquote>
<h4 id="RAID-5EE"><a href="#RAID-5EE" class="headerlink" title="RAID 5EE"></a>RAID 5EE</h4><p>RAID 5的缺点是不能坏两块盘，因为如果一块盘坏了，可以用其他数据校验出。<br>可在阵式中增加<code>热备盘</code>，不参与组阵，只有在损坏的时候立刻顶替，其他盘恢复数据。如果此时有请求此盘的IO，则其他盘暂代。</p>
<ul>
<li>RAID 5E :让阵中其他盘都从各自的领地里面保留出一块空间，作为热备盘。</li>
<li>RAID 5EE：热备盘融合到数据盘中，如校验盘一般。</li>
</ul>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-0b6d8127355cf3c9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h3 id="RAID-6"><a href="#RAID-6" class="headerlink" title="RAID 6"></a>RAID 6</h3><p>同样RAID 6也是为了解决RAID 5只能坏一块盘的问题。</p>
<p>如果坏了两块盘，相当于存在两个未知数，要求解两个未知数据，<strong>一定需要另外一个不相关的等式来求解。</strong></p>
<p>所以使用<strong>两套算法</strong>各自算出一个等式，分别放在两块校验盘中。</p>
<p>优点是更安全，缺点是<strong>写惩罚</strong>更大。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-36ccd35bc0a40d72.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h2 id="RAID-卡"><a href="#RAID-卡" class="headerlink" title="RAID 卡"></a>RAID 卡</h2><p><code>软件RAID</code>运行于操作系统底层，将SCSI 或者IDE控制器提交上来的物理磁盘，虚拟成虚拟磁盘，再提交给卷管理程序。但是</p>
<p>软件RAID ：</p>
<ul>
<li>占用内存空间</li>
<li>占用CPU</li>
<li>无法把操作系统盘做成RAID ：如果操作系统损坏了，就无法运行。</li>
</ul>
<p>既然软件这么多缺点，所以人们谋求用硬件来实现RAID的方法。<br>RAID卡就是利用独立硬件来实现RAID功能的方法。</p>
<p>一般在<strong>SCSI</strong>卡上增加了额外的芯片用于RAID功能。<br><img src="http://upload-images.jianshu.io/upload_images/1323506-0378a7cc51b42f7a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>SCSI RAID卡上一定要包含SCSI控制器，因为其后端连接依然是SCSI的物理磁盘。</p>
<h3 id="操作系统如何看待逻辑磁盘"><a href="#操作系统如何看待逻辑磁盘" class="headerlink" title="操作系统如何看待逻辑磁盘"></a>操作系统如何看待逻辑磁盘</h3><p>RAID控制器向OS提交的是<strong>虚拟逻辑盘</strong>，而非所有的物理磁盘。每个逻辑盘对<strong>OS来说都是一块单独的磁盘。</strong></p>
<p>比如安装了2块IDE磁盘和4块SCSI磁盘，IDE直接连接到IDE接口，SCSI连接到PCI接口的SCSI卡上。</p>
<p>若无RAID，可以看到6块硬盘。</p>
<p>可以通过RAID程序把两块IDE做成RAID 0 ， 变成了2*80G = 160G的磁盘。</p>
<p>4块SCSI磁盘做RAID 5，相当于3块盘的容量，即216GB。</p>
<p>所以磁盘管理器其实可以看到两块硬盘，可以格式化为NTFS等文件格式。</p>
<p><strong>与分区对比</strong></p>
<p>与分区不同，分区是OS在<strong>物理磁盘</strong>上做再次划分。而RAID 卡提供给OS的是任何时候是一块或者几块的逻辑盘，也就是OS认为的物理磁盘。</p>
<p>OS在磁盘上还可以进行分区，格式化。</p>
<blockquote>
<p>LUN：条带化以后，RAID程序操控SCSI控制器向OS层的驱动程序代码提交虚拟化之后的<strong>虚拟盘</strong>。</p>
</blockquote>
<h3 id="RAID-控制器如何管理逻辑磁盘"><a href="#RAID-控制器如何管理逻辑磁盘" class="headerlink" title="RAID 控制器如何管理逻辑磁盘"></a>RAID 控制器如何管理逻辑磁盘</h3><p>RAID 卡可以对逻辑磁盘进行再次的划分，既然要划分，必须对某块磁盘的某个区域划分给那块逻辑盘用心里有数，所以有必要在每块磁盘保留一个区域，记录划分信息、RAID类型以及组内的磁盘信息。这种统一的RAID信息格式：<strong>DDF 。</strong></p>
<p>RAID卡可针对总线上某几块磁盘做一种RAID类型，然后针对另几块磁盘做另一种RAID类型。</p>
<blockquote>
<p>一种<strong>RAID类型</strong>包含的磁盘共同组成了一个RAID GROUP  ,简称RG。</p>
</blockquote>
<p>逻辑盘就是从RG划分出来的，原则上不能跨RG来划分，因为RG的RAID类型不一样，性能就不一样。</p>
<h3 id="RAID-卡上的内存"><a href="#RAID-卡上的内存" class="headerlink" title="RAID 卡上的内存"></a>RAID 卡上的内存</h3><p>RAID卡上的内存，有数据缓存和代码执行内存的作用</p>
<ul>
<li>RAID 控制器和磁盘通道控制器之间需要一个缓存来适配。适配不同速率的通信</li>
<li>缓存数据IO：缓存队列，执行或者优化合并。</li>
</ul>
<h3 id="RAID卡的缓存"><a href="#RAID卡的缓存" class="headerlink" title="RAID卡的缓存"></a>RAID卡的缓存</h3><p>对于上层的写IO，有两种手段来处理；</p>
<ul>
<li>Write Back模式：将上层发来的数据保存在缓存中之后，立即通知主机IO完成，执行下一个IO。实际上此时数据还在缓存中，没有写入磁盘。RAID卡在空闲的时候，一条一条或者批量写入磁盘，其实是欺骗了主机。如果意外，数据丢失，上下数据不一致。<strong>需要使用电池来保护缓存。</strong></li>
<li>Write Through模式：只有在写入到磁盘之后才会通知主机，但是缓存的提速作用没有优势。缓冲作用依旧生效。</li>
</ul>
<p>对于<strong>读缓存</strong>：</p>
<ul>
<li><p>有一种算法叫<code>PreFetch</code>：预取，读缓存。其实就是认为主机下一次IO，有很大的几率是读取到所在磁盘位置的相邻数据。所以在主机还没发出读请求的时候，就先把相邻的数据读到缓存中。对大文件应用很适用。</p>
</li>
<li><p>还有一种缓存算法：假设主机的下一次IO可能还会读取上一次读过的数据。读了一段数据到缓存之后，如果数据被主机的写IO更改了，不会立即写入磁盘，而是留在缓存中。等到主机有一段时间不用了，则写入磁盘中。</p>
</li>
</ul>
<blockquote>
<p>中高端的RAID卡一般有256M的RAM作为缓存。</p>
</blockquote>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-38d1179ff38fc8f6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h2 id="卷管理层"><a href="#卷管理层" class="headerlink" title="卷管理层"></a>卷管理层</h2><p>到目前为止，我们已经可以通过RAID卡对外呈现一个一个的逻辑盘了，但是逻辑盘存在一个非常大的问题就是不够灵活。</p>
<p>如果一开始就划分一个100G的逻辑盘，如果数据盛不下了，此时把其他磁盘上未使用的空间挪一部分到逻辑盘上。</p>
<p>但是从RAID卡里面增加逻辑盘容量很费功夫。即使实现了，上层文件系统也无法立刻感知到。所以对要求不间断服务的服务器不适用。</p>
<p>归根结底，因为RAID控制器是由硬件来实现RAID的，所以操作起来不灵活，如果OS把RAID控制器提交上来的逻辑盘，加以组织和再分配。就非常灵活，其实就是<strong>加一层灵活的管理层。</strong></p>
<p><code>卷管理层</code>:Volume Manager，LDM（逻辑磁盘管理）</p>
<p>LVM开始是Linux系统上的一种实现，后来移植到AIX和HPUX等系统</p>
<ul>
<li>PV：OS识别的物理磁盘（或者RAID提交的），类似一块面团</li>
<li>VG：多个PV放到一个VG里面，VG(volume group)卷组。VG会将所有的PV首尾相连，<strong>组成逻辑上连续编址的存储池。</strong></li>
<li>PP：物理区块，Physical Partition，在逻辑上将一个VG分割为连续的小块。（把一大盆面掰成大小相等的无数块小面块）。LVM会记录PP的大小和序号的偏移。如果PV本身是经过RAID控制器虚拟化而成的LUN，扇区可能是位于若干条带中，物理上不一定连续。</li>
<li>LP：逻辑区块，可以对应一个PP，也可以对应多个PP，前者对应前后没有什么区别。后者又分为两种情况。<ul>
<li>多个PP组成一个大LP，像RAID 0 </li>
<li>一个LP对应几份PP，这几份PP每一份内容一样，类似RAID1。然后用一个LP来代表他们，往这个LP写数据，也就是写到了这个LP对应的几份PP中。</li>
</ul>
</li>
<li>LV：若干LP组成LV （逻辑卷），也就是LVM所提供最终可以用来存储数据的单位。生成的逻辑卷，在主机看来还是普通的磁盘，可以进行分区和格式化。</li>
</ul>
<p>大小可以随时变更，也不需要重启OS。前提是还有备用的PP。</p>
<p>操作很简单：创建PV，加入VG ，创建LV，格式化，随便扩展。</p>
<blockquote>
<p>最大的好处：生成的LV可以跨越RAID卡提交给OS的物理或者逻辑盘。</p>
</blockquote>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-a6bbb9d97d2101d0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h3 id="卷管理软件的实现"><a href="#卷管理软件的实现" class="headerlink" title="卷管理软件的实现"></a>卷管理软件的实现</h3><p>那么卷管理软件到底怎么实现的呢？</p>
<p>LVM会记录某块物理盘的名称、容量，谁是谁，从哪里到哪里是属于这块盘的，地址是多少等。这些信息记录在磁盘某个区域，LVM中这个区域叫<code>VGDA</code></p>
<p>LVM可以通过读取每块物理磁盘上的这个区域来获得LVM的配置信息，比如PP大小，初始偏移，PV的数量，排列顺序和映射关系等。</p>
<p>LVM初始化的时候读取信息，然后在缓存中生成<strong>映射公式</strong>，从而完成LV的挂载。如果此时上层来一个IO，LVM就需要通过缓存中的映射关系判断地址对应到实际物理磁盘的哪个地址。然后通过磁盘控制器驱动直接给这个地址发数据。这个地址被RAID控制器接收到了，还需要做一次转换。</p>
<blockquote>
<p>总之：卷管理软件就是运行在OS磁盘控制器驱动程序之上的软件，作用是实现RAID卡硬件管理磁盘空间所实现不了的灵活功能，比如随时扩容。</p>
</blockquote>
<p>磁盘在VM这一层处理之后，称为卷更为恰当。因为磁盘控制器看待磁盘，就是盘片+磁头，而卷管理软件看待磁盘，会认为它是一个<strong>线性的大仓库</strong>，而不管仓库用什么方式存储。</p>
<blockquote>
<p><strong>仓库</strong>的每个房间都有一个地址（LBA），VM只需要知道一共有多少，让<strong>库管员</strong>（磁盘控制器驱动）从某段地址（LBA地址段）存取货物（数据），那么库管员立即操控机器（磁盘控制器）来各个房间取货物（数据），这就是VM的作用。</p>
</blockquote>
<p>** 即从底到上依次是：物理磁盘、磁盘控制器、IO总线、总线驱动、磁盘控制器驱动、卷管理程序**</p>
<p>在底层磁盘扩容之后，磁盘控制器驱动程序会通知VM已经增大了多少容量</p>
<blockquote>
<p>扩大、收缩卷需要其上的文件系统来配合。</p>
</blockquote>
<h2 id="MBR-和VGDA"><a href="#MBR-和VGDA" class="headerlink" title="MBR 和VGDA"></a>MBR 和VGDA</h2><p>分区管理是最简单的卷管理方式，分区就是将一个磁盘抽象为一个仓库，然后将仓库划分为一库区、二库区等。</p>
<blockquote>
<p>分区管理和卷管理最大的不同在于，分区管理只能针对单个磁盘进行划分，而不能将磁盘进行合并再划分。</p>
</blockquote>
<p>分区信息保存在磁盘上，位于LBA1这个扇区，又称为MBR也就是主引导记录。</p>
<p>BIOS代码都是固定的，所以必定要执行MBR上的代码，新出来的规范EFI可以灵活定制从那个磁盘的哪个扇区启动，</p>
<p>MBR除了包含启动指令代码，还包含了<strong>分区表</strong>。启动的时候，程序会跳转到活动分区去读取代码做OS启动。所以必须有一个活动分区。</p>
<p>卷管理软件在划分了逻辑卷以后同样需要记录卷怎么划分的，使用一种叫VGDA的数据结构。</p>
<p>高级VM没有抛弃MBR，而是在此基础上，增加了类似VGDA的这样的数据结构来动态管理磁盘。</p>
<h2 id="文件系统"><a href="#文件系统" class="headerlink" title="文件系统"></a>文件系统</h2><p>文件系统相当于理货员，与库管员一起完成管理粮库的工作。</p>
<p>应用程序只需要告诉文件系统需要放多少的数据或者读多少数据，而文件系统不需要关心仓库到底在那里，放到那个房间。</p>
<p>文件系统需要将数据存放在那里记录下来。</p>
<blockquote>
<p>如果存取的数据量大，每次记录的数很大。将8个房间划分为一个逻辑房间，称作“簇”</p>
</blockquote>
<p>数据如果找连续的簇进行存放，则还必须花时间把整理仓库，整理出连续的空间来，所以不如在描述数据存放的方式，比如<code>数据 10000  簇2,6,18</code>，这样就可以解决空间浪费的问题，而且不需要经常整理库。</p>
<p>但是这样又存在一个问题，数据描述的方式变得长短不一，可以为了简化处理，需要给一个定长的描述。比如<code>数据 100000 首簇1</code>，然后在在首簇做一个标记，写明下一个簇是多少号，然后找到下一个簇，根据簇的路标，到下下个簇进行取货，依此类推。</p>
<p>如果要寻找空的簇，只需要找格子上没有写字的簇即可。</p>
<p>总结一下，</p>
<blockquote>
<p>描述货物的三字段：名称、数量、存放的第一个簇。</p>
</blockquote>
<p>进一步优化：</p>
<p>货物虽然有可能存放在不连续的簇中，但是这些簇往往也是局部连续的。所以如果是一段一段的找而不是一簇一簇的找，会节约时间。比如簇段1<del>3，簇段5</del>7等等。</p>
<blockquote>
<p>所以记录数据存放信息的本子就是元数据，也就是用来描述数据怎么组织的数据。</p>
</blockquote>
<p>如果记录本丢失，纵然货物无损，也无法取出，因为无法判断货物的组织结构了。</p>
<h2 id="文件系统的IO方式"><a href="#文件系统的IO方式" class="headerlink" title="文件系统的IO方式"></a>文件系统的IO方式</h2><p>IO Manager是OS内核中专门来管理IO的模块，可以协调文件系统、磁盘驱动的运作，流程如下</p>
<ul>
<li>应用调用文件系统接口</li>
<li>IO Manager把请求发送给文件系统模块</li>
<li>文件系统映射为卷的LBA</li>
<li>文件系统向IO Manager调用卷管理软件模块的接口</li>
<li>卷管理软件将卷对应的LBA反映为实际的LBA，并请求调用磁盘控制器驱动程序。</li>
<li>IO Manager向磁盘控制器驱动程序请求将对应的LBA段从内存写入到物理磁盘。</li>
</ul>
<p><strong>文件系统IO：</strong></p>
<ul>
<li><strong>同步IO</strong>：进程调用了IO以后，必须等到下位程序返回信号，否则一直等待，被挂起。<br>如果下位程序没有得到数据<ul>
<li><strong>阻塞IO</strong>：下位程序等待自己的下位程序返回数据。</li>
<li><strong>非阻塞IO</strong>：通知上位程序数据没收到。</li>
</ul>
</li>
<li><strong>异步IO</strong>：请求发出以后，执行本线程的后续代码，直到时间片到或者被挂起。这样应用程序的响应速度不会受IO瓶颈的影响，即使这个IO很长时间没有完成。</li>
</ul>
<p>异步IO和非阻塞IO另一个<code>好处</code>：文件系统不需要等待及时返回数据，可以对上次的IO进行优化排队。</p>
<p><strong>Direct IO</strong>：文件系统有自己的缓存机制，数据库也有缓存，IO发出之前已经经过自己的优化了，如果又在文件系统层面再优化一次，多次一举。使用<code>Direct IO</code>以后IO请求、数据请求以及回送数据不被文件系统缓存，直接进入应用程序的缓存中，可以提升性能。此外，在系统路径上任何一处引入了缓存，若采用write back模式，都存在数据一致性的问题，因为Direct IO绕过了文件系统的缓存，降低了数据不一致性。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-14f45ffcefc98ba8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

        
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="en">
    <link itemprop="mainEntityOfPage" href="https://duyang2903.gitee.io/2019/11/15/%E5%A4%A7%E8%AF%9D%E5%AD%98%E5%82%A8%EF%BC%8C%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%8810~13%E7%AB%A0%EF%BC%89%EF%BC%8CNAS%E3%80%81IP-SAN/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="dy2903">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="dy2903的博客">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          
            <a href="/2019/11/15/%E5%A4%A7%E8%AF%9D%E5%AD%98%E5%82%A8%EF%BC%8C%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%8810~13%E7%AB%A0%EF%BC%89%EF%BC%8CNAS%E3%80%81IP-SAN/" class="post-title-link" itemprop="url">大话存储，学习笔记（10~13章），NAS、IP-SAN</a>
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">Posted on</span>

              <time title="Created: 2019-11-15 10:48:24" itemprop="dateCreated datePublished" datetime="2019-11-15T10:48:24+08:00">2019-11-15</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">Edited on</span>
                <time title="Modified: 2019-11-13 21:27:13" itemprop="dateModified" datetime="2019-11-13T21:27:13+08:00">2019-11-13</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="DAS-SAN-NAS"><a href="#DAS-SAN-NAS" class="headerlink" title="DAS , SAN , NAS"></a>DAS , SAN , NAS</h1><h2 id="NAS"><a href="#NAS" class="headerlink" title="NAS"></a>NAS</h2><p>LUN只是一个卷设备，对主机而言就是一块硬盘，我们的操作系统集成了文件系统的功能，可以用来管理卷。而 NAS就是把文件系统从主机迁移到磁盘阵列上，自己来管理。使用者只需要通过网络告诉这个文件系统需要存取什么文件而不需要向NAS传递LBA地址。</p>
<p>那么** NAS与SAN的区别**是什么？<br>SAN是网络上的磁盘，NAS是网络上的文件系统。</p>
<ul>
<li><p>SAN：存储区域网络，是网络上的磁盘，其本质只是一个<strong>网络</strong>，包含了主机、适配器等一切后端存储相关的内容。可以说SAN包含NAS。</p>
</li>
<li><p>一般把FC网络上的磁盘叫做SAN，以太网上的文件系统叫NAS</p>
</li>
</ul>
<p>另外， FTP服务器属于NAS吗？不属于，为什么？</p>
<p>我们知道网络文件系统与本地文件系统最大的<strong>区别</strong>是传输方式从主板的导线变成了<strong>以太网络</strong>，也就是传输的距离可以更快了。但是FTP实际上必须把文件传输到本地的某个目录才能执行，而网络文件系统不需要将数据复制到本地再进行访问，可以进行挂载。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-86123a12be4bdd76.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h2 id="NAS与SAN之争"><a href="#NAS与SAN之争" class="headerlink" title="NAS与SAN之争"></a>NAS与SAN之争</h2><h3 id="谁更快"><a href="#谁更快" class="headerlink" title="谁更快"></a>谁更快</h3><p>NAS主要实现虚拟目录层与文件系统层的通信，使用的是“以太网+TCP/IP”，为了处理TCP/IP和以太网逻辑，增加了不少的CPU指令，同时使用的是以太网等低速介质。</p>
<p>而FC SAN中，FC逻辑有很大一部分由HBA卡完成，同时FC协议的速度比以太网更快，所以整体来说FC SAN肯定更快。</p>
<p>但是在<strong>大量随机小块IO</strong>的场景下，因为NAS系统对并发IO进行了优化，而且文件系统逻辑由专门的设备处理，所以性能可能会比SAN更高。</p>
<p>既然这样，为什么还需要使用NAS呢？因为</p>
<ul>
<li>最重要的文员是<strong>NAS成本更低</strong>，不需要昂贵的FC HBA卡和FC交换机。</li>
<li>基于以太网、TCP/IP，扩展性强</li>
<li>可以提供多种协议访问。网络文件系统通过HTTP、FTP等协议进行访问，而SAN只有SCSI协议。</li>
<li>采用专门的设备处理文件系统逻辑， 可以解放主机CPU和内存，适合在CPU密集的应用环境。</li>
<li>NAS可以在一台盘阵上实现多台客户端同时访问。SAN的LUN一般只能分配给某个主机，只有通过<strong>集群系统</strong>对数据一致性进行了保证以后，才能实现LUN共享</li>
</ul>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-85de1e97b83b5844.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>所以单纯的讨论** SAN好还是NAS好**是没有意义的，我们更需要的是根据场景、成本等要素来决定到底使用NAS还是SAN。</p>
<p>我们可以把目前的应用分为两种：IO密集与CPU密集</p>
<ul>
<li><p>CPU密集：程序内部逻辑复杂，但是对磁盘IO访问量不高。比如高性能运算</p>
</li>
<li><p>IO密集：内部逻辑不复杂，但是需要随时存取硬盘的，比如Web应用</p>
</li>
<li><p>IO和CPU同时密集：不适合单机运行，需要组成集群</p>
</li>
</ul>
<p>对于<strong>高并发随机小块IO</strong>，或者共享访问文件的环境，因为NAS做了很多的优化，此时应该优选NAS。而对于大块<strong>顺序IO</strong>密集的环境，NAS比SAN慢，所以优选SAN。</p>
<h3 id="与SAN和与NAS设备通信的过程"><a href="#与SAN和与NAS设备通信的过程" class="headerlink" title="与SAN和与NAS设备通信的过程"></a>与SAN和与NAS设备通信的过程</h3><p>对主机而言，如果与SAN通信，必须通过文件系统。当应用程序发出指令后，<strong>文件系统</strong>会计算LBA地址，然后通过FC网络告诉SAN。SAN取出数据，通过FC网络传送给主机，然后放入程序的缓冲区。</p>
<p>那与NAS设备通信呢？程序只需要告诉NAS设备<strong>路径+文件</strong>即可，也就是说通过操作系统的<strong>虚拟目录</strong>与NAS进行对话，通过TCP/IP+以太网进行传输，后面的过程就都在NAS设备内部了，它会查找要取的文件的扇区位置，存储数据。</p>
<p>其实NAS设备还可以进行拆分，它可以把<strong>硬盘拆分出去</strong>，只是做为一个<strong>专门处理文件逻辑的设备</strong>而存在，这就是<strong>NAS网关</strong></p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-e82a0b725e4fb298.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h2 id="DAS、NAS、SAN"><a href="#DAS、NAS、SAN" class="headerlink" title="DAS、NAS、SAN"></a>DAS、NAS、SAN</h2><blockquote>
<p>DAS：最原始的存储：直接存储。存储设备只用与独立的主机。比如PC中的磁盘或者只有一个外部SCSI接口的JBOD</p>
</blockquote>
<p>DAS（仅供自己使用）到SAN（出租仓库给其他的租户），到NAS(集中式理货服务外包)</p>
<p>SAN是一种网络，而不是某种设备。只要是专门向服务器传输数据的网络就可以称为SAN。</p>
<p>NAS设备通过以太网向主机提供文件级别的数据访问，以太网络就是SAN。</p>
<p>习惯性的将FC SAN架构称为SAN</p>
<h2 id="NetApp的NAS"><a href="#NetApp的NAS" class="headerlink" title="NetApp的NAS"></a>NetApp的NAS</h2><p>NetApp的NAS极大的借鉴了数据库管理系统的设计，本小节主要讲解一下NetApp的NAS的基本思想。</p>
<h3 id="利用了数据库管理系统的设计"><a href="#利用了数据库管理系统的设计" class="headerlink" title="利用了数据库管理系统的设计"></a>利用了数据库管理系统的设计</h3><p>我们知道<strong>数据库管理系统</strong>是这样记录日志的，在某个时刻，数据库管理系统接收到应用程序的SQL更新语句，首先将数据修改前的状态以日志的形式保留在<strong>内存的日志缓存区</strong>，然后覆写原来的数据。</p>
<p>因为日志缓存区是内存的一部分，所以如果掉电则数据丢失，所以每隔一段时间或者说程序进行<strong>提交事务时</strong>，管理系统会把日志推到磁盘中。同理，也会把缓存中更新过的数据块写入磁盘。</p>
<p><strong>只有当日志确实写入到硬盘上的日志文件中的时候，才会对上层应用返回执行成功。</strong><br>具体过程可以参见<a href="https://www.jianshu.com/p/769b6971e528" target="_blank" rel="noopener">数据库（五），事务</a>。</p>
<p>NetApp借鉴了这种设计思想，它会将<strong>文件系统</strong>中的<strong>写入请求</strong>作为操作日志写入到NVRAM中保存。</p>
<blockquote>
<p>NVRAM不用电池也可以在不供电的情况下保存数据，而NetApp使用的是<strong>带电池保护的</strong>RAM，下文姑且称其为NVRAM.</p>
</blockquote>
<p><strong>为什么要使用NVRAM而不像数据库一样使用文件来保存日志的呢？</strong></p>
<p>对于数据库系统来说，先将日志写入到内存中日志缓冲区，再在触发条件下将日志写入磁盘上的文件。一旦意外掉电，内存中的日志没有来得及保存到硬盘就丢失，数据库再次启动的时候，会提取硬盘上的日志，对于没有提交的操作进行回滚。这样就保证了数据的一致性。</p>
<p>不过如果应用程序频繁提交，日志缓冲区的日志会频繁的写入到磁盘上，这时日志缓存就起不了什么作用了。 </p>
<p>对数据库来说，上层的每个业务一般都算是一个交易，在尚未完成的时候，程序不会发送提交指令给数据库系统的，所以频繁提交的<strong>频率不高</strong>。</p>
<p>而文件系统则不然，上层应用向文件系统写入数据而言，每次请求都是完整的交易。也就是说提交会非常频繁。如果将操作日志写入磁盘，开销大，所以利用了带电池保护的RAM内存（NVRAM）。只要成功写入了RAM，就可以立即通知上层写入成功。</p>
<p>一定要搞清楚日志和数据缓存的区别。</p>
<ul>
<li>日志是记录操作动作和数据内容，而非实际的数据块。保存在NVRAM中</li>
<li>实际的数据块保存在RAM中而非NVRAM中。</li>
</ul>
<p>WAFL的做法是用RAM来保存日志，可以一次接收到上千条写请求，而且可以直接返回成功。等到RAM半满，由WAFL一次性批量连续写入硬盘，保证高效率。</p>
<h3 id="WAFL从不覆写数据"><a href="#WAFL从不覆写数据" class="headerlink" title="WAFL从不覆写数据"></a>WAFL从不覆写数据</h3><blockquote>
<p>当日志占了NVRAM空间的一半或者每10s，WAFL会将内存中已改写的数据以及元数据批量写入硬盘。同时清空日志，腾出空间。这个动作叫<code>CheckPoint</code></p>
</blockquote>
<p>WAFL不会覆盖掉对应区块中原来的数据，而是寻找空闲块来存放被更改的块。也就是说WAFL写入的数据都会到空闲块中，而不是覆盖旧块。另外，在Checkpoint没有发生或者数据没有Flush完全之前，WAFL从来不会写入任何元数据到磁盘。</p>
<p>这样可以保证CheckPoint没发生之前，磁盘上的元数据对应的实际数据仍为上一个CheckPoint的状态。如果此时断电，就算新数据写入了，但是元数据没有写入，所以磁盘上的元数据仍指向旧块，数据就像没有变化，所以不用执行文件系统检查等工作。</p>
<p>当CheckPoint触发时，<strong>先写入数据，最后再写元数据</strong>，然后新元数据指针指向方才写入的新数据块。对应的旧数据块变为空闲块。（此时块中仍然有数据，但是没有任何指针指向它）<br><img src="http://upload-images.jianshu.io/upload_images/1323506-abd277a5aeb547f4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h1 id="IP-SAN"><a href="#IP-SAN" class="headerlink" title="IP SAN"></a>IP SAN</h1><p>以太网的可寻址容量大，比IP都大，而且地址是定长的，使用专用的电路完成交换，还可以使用光纤进行传输。最重要的一点是以太网非常的廉价。</p>
<p>但进入以太网有这么多优点，现在FC SAN还是应用广泛，这是因为以太网与FC相比，以太网是不可靠的网络，不是端到端的协议，必须依靠上层协议。而且开销也比较大。</p>
<h2 id="IP-SAN-1"><a href="#IP-SAN-1" class="headerlink" title="IP SAN"></a>IP SAN</h2><p>TCP/IP在速度和性能上无法与FC相比，但是它最大的优点在于扩展性，SCSI都能嫁接到FC上，当然也可以与TCP/IP结合。这种新的协议系统叫<code>ISCSI（Internet Small Computer System Interace ）</code>。</p>
<p>这种协议的优点很明显，只要IP可达，两个节点就可以通过ISCSI通信。所以扩展性非常强。</p>
<blockquote>
<p>IP SAN ： 以ISCSI为代表的TCP/IP作为传输方式的网络存储系统，也就是基于IP的存储区域网络</p>
</blockquote>
<p>当然<strong>IP SAN不一定用以太网作为链路层</strong>，可以用任何支持IP 的链路层，如 ATM 、PPP 、 HDLC 甚至是FC </p>
<p>同样用TCP/IP来进行传输，NAS与IP SAN有什么区别呢？</p>
<p>NAS传输的是文件系统语言。ISCSI传输是SCSI指令语言。所以IP SAN本质是SAN提供的是块存储</p>
<p>IP SAN相对于FC SAN最大的优势在于：</p>
<ul>
<li><p>FC SAN 成本是IP SAN的十倍。</p>
</li>
<li><p>FC是专用网络，很难扩展</p>
</li>
<li><p>部署FC存储网络更复杂</p>
</li>
<li><p>兼容性：不同生产厂家的FC设备不一定完全兼容</p>
</li>
</ul>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

        
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="en">
    <link itemprop="mainEntityOfPage" href="https://duyang2903.gitee.io/2019/11/15/%E5%A4%A7%E8%AF%9D%E5%AD%98%E5%82%A8%EF%BC%8C%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%8815%E7%AB%A0%EF%BC%89%EF%BC%8C%E5%AF%B9%E8%B1%A1%E5%AD%98%E5%82%A8/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="dy2903">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="dy2903的博客">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          
            <a href="/2019/11/15/%E5%A4%A7%E8%AF%9D%E5%AD%98%E5%82%A8%EF%BC%8C%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%8815%E7%AB%A0%EF%BC%89%EF%BC%8C%E5%AF%B9%E8%B1%A1%E5%AD%98%E5%82%A8/" class="post-title-link" itemprop="url">大话存储，学习笔记（15章），对象存储</a>
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">Posted on</span>

              <time title="Created: 2019-11-15 10:48:24" itemprop="dateCreated datePublished" datetime="2019-11-15T10:48:24+08:00">2019-11-15</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">Edited on</span>
                <time title="Modified: 2019-11-13 21:27:14" itemprop="dateModified" datetime="2019-11-13T21:27:14+08:00">2019-11-13</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>在谈对象存储是什么之前，我们先回顾一下块存储和文件存储是什么</p>
<h1 id="块存储与文件存储"><a href="#块存储与文件存储" class="headerlink" title="块存储与文件存储"></a>块存储与文件存储</h1><h2 id="块存储："><a href="#块存储：" class="headerlink" title="块存储："></a>块存储：</h2><p>常见的块存储设备是<strong>磁盘阵列</strong>，它会向主机提供<strong>裸磁盘</strong>空间。也就是说操作系统看到的只是一块磁盘而已，虽然它底层可能是多块硬盘组合起来的逻辑盘。</p>
<p>这种方式下，操作系统还可以对挂载的裸硬盘进行分区、格式化，与主机内置的硬盘使用没有区别。</p>
<p>一般块存储会采用SAN架构组网，而且会使用FC 协议，这样传输速度和吞吐量都会很大。但是也正因为需要使用FC协议，自然也需要FC HBA卡以及FC交换机，成本将比较高。</p>
<p>另外，磁盘阵列一般会把某一块LUN映射给某个主机，也就是说这块主机独享这块LUN，就相当于它的本地盘，自然无法与其他的主机共享数据。<br><img src="http://upload-images.jianshu.io/upload_images/1323506-8d4aa8e6758c9d4c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h2 id="文件存储"><a href="#文件存储" class="headerlink" title="文件存储"></a>文件存储</h2><p>块存储很难解决文件共享的问题，因为主机的操作系统可能不一样，所以文件管理系统也不一样，那么能不能把文件系统单拿出来，放到某一专用的设备上呢？当然可以，这就形成了文件存储系统，最经典的当属NAS设备。</p>
<p>简单的说，NAS设备就是把文件管理功能移植到专用的设备上，而且只需要以太网就可以，成本大大降低。</p>
<p>缺点也很明显，传输速率远远赶不上SAN网络。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-2a48eb2b842204d8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h1 id="对象存储系统"><a href="#对象存储系统" class="headerlink" title="对象存储系统"></a>对象存储系统</h1><h2 id="对象存储怎么来的"><a href="#对象存储怎么来的" class="headerlink" title="对象存储怎么来的"></a>对象存储怎么来的</h2><p>我们知道块存储、文件存储各有其优缺点，简单的说，块存储读写块，但是不利于共享，文件存储读写慢，但是利于共享。</p>
<p>有没有一种方式，可以克服他们的优缺点呢？也就是读写快，同时利于共享。要想读写快，最好的方法是<strong>并行</strong>取，要想共享，最好能结合文件系统的特点。既然如此，我们先再看看文件存储有没有什么可以借鉴的地方吧。</p>
<p>在文件系统里面，一个文件包含了<strong>元数据以及内容</strong>，比如FAT32这种文件系统，文件数据与元数据一起存放的。当你要存放一个文件的时候，首先会划分为4k大小的块，然后写到硬盘里面，注意切分的时候会不区分数据和元数据。</p>
<p>每个块都会指向下一个块的地址，所以读取的时候只能一个一个顺序的查找，速率自然上不去。具体实现方式可见<a href="http://www.cnblogs.com/dy2903/p/8367217.html" target="_blank" rel="noopener">http://www.cnblogs.com/dy2903/p/8367217.html</a></p>
<p>后来我们把主机的文件系统移植到专门的NAS设备上，主机要访问某个文件只需要传递<strong>路径和文件名</strong>即可。也就是说NAS设备其实就是把“文件——块”的映射关系移植到了专门的设备里面。如下图所示。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-6497493c85f715b4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>传统的NFS架构，一个目录只能载入一次，所有的请求只能发与它，哪怕是这个目录下的文件实际上是存在另一个节点上，也需要通过此节点进行转发，无法并行。</p>
<p>那我们能不能故技重施，把磁盘也挪出去，组成集群，然后文件系统可以并行的访问这些磁盘呢。</p>
<p>但是主机客户端怎么知道要访问的文件在哪个磁盘上呢？再不能在客户端本地维护一份映射关系吧。解决的方法是<strong>维护元数据</strong>的功能也剥离出来，形成一个独立的<strong>元数据服务器</strong>，由它来维护“文件——磁盘——块”之间的映射关系。</p>
<p>那么如果客户端要访问文件，首先需要向元数据服务器发起请求，由它来告知需要文件存放的具体位置。之后，客户端可以直接向磁盘发出IO请求。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-bb08f35f8414a425.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>总结一下就是将<strong>文件系统逻辑从主机端移出来放到元数据服务器上，所有的硬盘也放到网络中</strong></p>
<p>不过这个架构需要硬盘非常的智能，因为要把很多逻辑放到硬盘上来处理，到目前来说也没有实现。没有关系，我们把硬盘换成Server就可以了，取名为<strong>对象存储设备(Object Storage Device， OSD)</strong></p>
<p>那么<strong>对象存储</strong>就是把<strong>元数据</strong>独立出来，成为<strong>元数据服务器</strong>，主要作用是存储对象数据的元数据。而其他实际存放文件数据部分的节点就叫<strong>OSD</strong>。文件我们改称为<code>Object</code>，目录称为<code>Partition</code>，OSD中每个Object用一个128b的Object ID(OID)表示，其实就类似NAS中的File Handle（文件句柄）</p>
<p>那么用户访问对象的时候，首先需要向元数据服务器请求对象存储在哪些OSD里面，然后用户才会向这些OSD服务器再次请求。可以看出，这样可以实现多台节点并行传输数据，速度自然加快。</p>
<p>同时因为对象存储是有专门的文件系统的，OSD节点又相当于文件服务器，所以可以解决文件共享的问题。</p>
<p>总的来说，对象存储结合了块存储和文件存储的优点。</p>
<h2 id="访问的流程"><a href="#访问的流程" class="headerlink" title="访问的流程"></a>访问的流程</h2><p>下图为对象存储的整体架构，其中元数据服务器、OSD服务器之前已经讲过了，我们还需要在主机上安装一个代理<code>OSD Initiator</code>。</p>
<p>如果用户想读取或者写入文件的时候，首先由这个代理向元数据服务器中查询文件存储的OSD设备，然后也是由它与操作系统的虚拟目录层对接，翻译成对应的OSD 请求，发给OSD。而且代理只需要给出<strong>OID</strong>即可，不需要给出绝对路径。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-e9708118ff375b65.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h2 id="与集群分布式文件系统的区别"><a href="#与集群分布式文件系统的区别" class="headerlink" title="与集群分布式文件系统的区别"></a>与集群分布式文件系统的区别</h2><p>我们可以再对比一下对象存储与集群分布式文件系统的区别。</p>
<p>集群文件系统架构中，客户端只能从某台节点上挂载某个目录，如果请求的数据不在这个节点上，会由它来进行重定向，那么这个节点的性能将成为瓶颈。</p>
<p>而OSD则不然，在开始访问之前，需要从元数据服务器上查询目标文件分布在哪些OSD节点上，然后才会<strong>并行</strong>的向相关节点发起IO请求，并行的存储数据，简单的讲对象存储既有块存储的高效率，又有文件存储的灵活性。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-8f57b541639b9d2a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

        
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="en">
    <link itemprop="mainEntityOfPage" href="https://duyang2903.gitee.io/2019/11/15/%E5%A4%A7%E8%AF%9D%E5%AD%98%E5%82%A8%EF%BC%8C%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%8816%E7%AB%A0%EF%BC%89%EF%BC%8C%E6%95%B0%E6%8D%AE%E4%BF%9D%E6%8A%A4%E5%92%8C%E5%A4%87%E4%BB%BD%E6%8A%80%E6%9C%AF/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="dy2903">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="dy2903的博客">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          
            <a href="/2019/11/15/%E5%A4%A7%E8%AF%9D%E5%AD%98%E5%82%A8%EF%BC%8C%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%8816%E7%AB%A0%EF%BC%89%EF%BC%8C%E6%95%B0%E6%8D%AE%E4%BF%9D%E6%8A%A4%E5%92%8C%E5%A4%87%E4%BB%BD%E6%8A%80%E6%9C%AF/" class="post-title-link" itemprop="url">大话存储，学习笔记（16章），数据保护和备份技术</a>
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">Posted on</span>

              <time title="Created: 2019-11-15 10:48:24" itemprop="dateCreated datePublished" datetime="2019-11-15T10:48:24+08:00">2019-11-15</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">Edited on</span>
                <time title="Modified: 2019-11-13 21:27:14" itemprop="dateModified" datetime="2019-11-13T21:27:14+08:00">2019-11-13</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="数据保护"><a href="#数据保护" class="headerlink" title="数据保护"></a>数据保护</h1><blockquote>
<p>所谓数据保护是指对<strong>当前时间点</strong>上的数据进行备份，<br>如果说一份数据被误删除了，可以通过<strong>备份数据</strong>找回来。</p>
</blockquote>
<p>从底层来分，数据保护可以分为文件级保护和块级保护。</p>
<h2 id="文件级备份"><a href="#文件级备份" class="headerlink" title="文件级备份"></a>文件级备份</h2><blockquote>
<p>文件级备份：将磁盘上所有文件通过<strong>调用文件系统接口</strong>备份到另一个介质上。也就是把数据以文件形式读出，然后存储在另一个介质上面。</p>
</blockquote>
<p>此时备份软件只能感知到<strong>文件</strong>这一层。</p>
<p>我们知道一般来说，文件在原来的介质上，可以是不连续存放的，通过文件系统来管理和访问。当备份到新的介质上以后，文件完全可以<strong>连续存放</strong>。正因为如此，没有必要备份<strong>元数据</strong>，因为利用新介质进行恢复的时候，反正会重构文件系统。</p>
<h2 id="块级备份"><a href="#块级备份" class="headerlink" title="块级备份"></a>块级备份</h2><blockquote>
<p>块级备份就是不管块上是否有数据，不考虑文件系统的逻辑，备份块设备上的每个块。</p>
</blockquote>
<p>这样好处是不通过调用文件系统接口，速度更快，缺点的是备份的时候会把所有的块复制一遍，但是实际上很多扇区的数据是不对应真实文件的，也就是会备份很多僵尸扇区。而且备份之后，原来不连续的文件一样是不连续的文件，有很多的碎片。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-a6bced62fd116930.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h1 id="高级数据保护"><a href="#高级数据保护" class="headerlink" title="高级数据保护"></a>高级数据保护</h1><h2 id="远程文件复制"><a href="#远程文件复制" class="headerlink" title="远程文件复制"></a>远程文件复制</h2><blockquote>
<p>远程文件复制：通过网络传输到<strong>异地容灾点</strong>。典型的代表是rsync异步远程文件同步软件。可以监视文件系统的动作，将文件的变化，同步到异地站点。增量复制。</p>
</blockquote>
<h2 id="远程卷镜像"><a href="#远程卷镜像" class="headerlink" title="远程卷镜像"></a>远程卷镜像</h2><p>这是基于<strong>块</strong>的远程备份。与<code>远程文件复制</code>不同的地方在于，是把<strong>块数据</strong>备份到异地站点。又可以分为同步和异步复制。</p>
<ul>
<li>同步复制：必须等数据复制到<strong>异地站点</strong>以后，才通报上层IO成功消息</li>
<li>异步复制：写入成功即可回复成功，然后通过网络传输到异地。不能保证一致性，但是上层响应快。</li>
</ul>
<p>基于块的备份措施，一般都是在底层设备上进行，不耗费主机资源。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-169005807c63817b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h2 id="快照"><a href="#快照" class="headerlink" title="快照"></a>快照</h2><p>远程镜像确实是对生产数据一种非常好的保护，但是需要镜像卷一直在线，主卷有写IO，那么镜像卷也需要有写IO。</p>
<p>如果想对<strong>镜像卷</strong>进行备份，需要将停止主卷的读写，然后将两个卷的镜像关系分离。所以当恢复主卷的IO的时候，镜像卷不会再被读写。然后才可以备份镜像卷的数据。</p>
<p>这样会存在一个问题，主卷上还继续有IO，将会导致数据与备份的镜像不一致。所以主卷上所有的写IO动作，会以位图bitmap方式记录下来，bitmap上的每个位表示卷上的一个块，0表示未写入，1表示已写入，所以当拆分镜像以后，被写入了数据，程序将bitmap文件对应位从0变为1。备份完成以后，再做数据同步即可。</p>
<p>可以看出上述过程比较的繁琐，而且需要占用一块和主卷一样大小的镜像卷。</p>
<p>快照技术就是为了解决这种问题，其<strong>基本思想</strong>是抓取某一时间点磁盘卷上的所有数据。<br><img src="http://upload-images.jianshu.io/upload_images/1323506-b42ac31f42c25652.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>快照分为：基于文件系统的快照和基于物理卷的快照</p>
<p>下面介绍一下快照的底层原理。</p>
<h3 id="基于文件系统的快照"><a href="#基于文件系统的快照" class="headerlink" title="基于文件系统的快照"></a>基于文件系统的快照</h3><blockquote>
<p>文件系统管理的精髓：链表、B树、位图，也就是元数据</p>
</blockquote>
<p>文件系统</p>
<ul>
<li><p>将扇区组合成更大的逻辑块来降低管理规模。NTFS最大块可以到4KB，也就是8个扇区一组一个簇（Block），这样可以减少管理成本。</p>
</li>
<li><p>文件系统会创建所管理存储空间上所有簇的<strong>位图</strong>文件。每个位代表卷上的簇（或者物理扇区）是否被使用，如果被使用，则置1。</p>
</li>
<li><p>文件系统保存一份文件和其对应簇号的映射链。因为映射链本身和簇位图也是文件，也有自己的映射链，所以针对重要的元数据，有一个固定的入口：<code>root inode</code></p>
</li>
</ul>
<p>写入新数据</p>
<ul>
<li><p>查找簇位图，找位值为0的簇号，</p>
</li>
<li><p>计算所需空间， 分配簇号给文件</p>
</li>
<li><p>将数据写入簇，再去<code>文件——簇号映射图</code>更新</p>
</li>
<li><p>将对应的簇映射关系记录下来，到簇位图将对应位置改为1.</p>
</li>
</ul>
<p>删除数据</p>
<ul>
<li><p>直接在簇号映射链中抹掉，</p>
</li>
<li><p>簇位图对应簇改为0</p>
</li>
</ul>
<p>可以看出删除数据实际上不会抹掉实际的数据。</p>
<p>** 所以，最重要的不是数据，而是文件——<code>簇号映射链和位图</code>等元数据。**</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-b4b02e5a773252dd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>也就是说我们要做备份，<strong>只需要把某时刻的文件系统中的映射图表保存下来。</strong>但是必须保证卷上的数据不被IO写入了，同时又要不应用还不能中断。既然原来的空间不能再写了，我们可以写到其他的<strong>空闲区域。</strong></p>
<ul>
<li><p>思路一：Copy on First Write (CoFW)，</p>
<p>  在覆盖数据块之前，需要将被覆盖的数据块内容复制出来，放到空闲的空间。</p>
<p>  系统中将有两套元数据链，<strong>原来的元数据指向当前，快照的元数据链指向历史</strong>。原来的存储空间永远是最新的数据，历史数据会逐渐搬出到空闲空间里面。</p>
</li>
</ul>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-34bfa59207890ccb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-583efc2c5ddb3b51.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<ul>
<li><p>思路二：Redirect on First Write,(RoFW)。</p>
<p>  先复制元数据，然后将针对<strong>源文件</strong>的更改都<strong>重定向</strong>到空余空间，同时<strong>更新元数据</strong>。</p>
<p>  与<code>CoFW</code>不同的是，原来的数据块不会被覆盖。同样的，系统也有两套元数据，一套是快照保存下来的，永远不更新，一套是源文件系统的，不断的更新。</p>
<p>  <strong>其实只有首次覆盖的时候，才重定向，因为重定向以后的数据块，哪怕被覆盖了，也不影响之前快照保存的数据了。</strong></p>
</li>
</ul>
<p>下图为生成两个快照之后系统处理流程。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-d793249e5cd493dd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"><br>[图片上传失败…(image-5cb224-1518689106646)]</p>
<p>到这一步，看上去挺完美，实际上存在一个问题：如果<code>元数据</code>特别大怎么办？对于海量庞大的文件系统，元数据量可能到GB级别。如果复制的话，时间上仍然太多。</p>
<p>我们可以回头想想，实际上元数据可以看做指针，指向具体存储的位置。我们复制到元数据，相当于复制了一堆指针。现在元数据太多了，我们能不能把这个<strong>元数据链</strong>的指针给复制了？当然可以，元数据有个<code>根入口块</code>，或者称为<code>Super Block</code>，这个块是固定不变的，里面存放有指向下一级元数据链块的指针。</p>
<p>那么操作系统每次载入元数据的时候，都需要从这个地址读入Super Block，从而一层一层的遍历。</p>
<p>下图为只复制Super Block以后的RoFW模式：</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-da025bc9a1a55a3e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h3 id="基于物理卷的快照"><a href="#基于物理卷的快照" class="headerlink" title="基于物理卷的快照"></a>基于物理卷的快照</h3><p>基于物理卷的快照比文件系统快照要简单得多。因为LUN一般在底层磁盘上是恒定的，不像文件系统一样可以随机细粒度的分布。所以可以认为<strong>LUN的元数据就是在底层磁盘的起始和结束地址</strong></p>
<p>这样在快照的时候，需要复制的元数据就更少了，但是完成了以后，需要按照一定粒度来做CoFW或者RoFW，还需要记录更多数据映射指针，就比较难受了。</p>
<p>对于实现了<strong>块级虚拟化</strong>的系统如NetApp,XIV,3PAR等，它们的LUN在底层位置是不固定的，LUN就相当于一个文件，存在元数据链来进行映射管理的维护，所以这些系统实现快照的原理与文件系统快照类似。</p>
<p>基于物理卷的快照，相当于给物理卷增加了“卷扇区映射管理系统”。在底层卷实现快照，可以减轻文件系统的负担。</p>
<p>卷扇区方都是用LBA来编号的，实现快照的时候，程序首先保留一张<strong>初始LBA表</strong>，每当有新的写入请求的时候，重定向到另一个地方，并在初始的LBA表中做好记录。比如</p>
<blockquote>
<p>原始LBA：卷A的10000号，映射到LBA：卷B的100号。</p>
</blockquote>
<p>值得说明的是，<strong>文件系统无法感知重定向，文件系统在它的映射图里面还是记录了原始的LBA地址</strong>。</p>
<p>此时如果来了新的写IO，有两种方式一种是Write Redirect 一种是Copy on Write</p>
<p>所谓Write Redirect就是将文件系统的读写请求，重定向到卷B，这样每次IO其实都会查找快照映射表，降低了性能。所以引入了Copy on Write</p>
<p>所谓Copy on write，就是当写请求来的时候，先把原来的扇区的数据复制一份到空闲卷，然后将新数据写入原卷。不过这种复制操作只发生在<strong>原卷某个或者快照之后从未更新过的块</strong>上面，若是某个块在快照之后更新过了，说明之前的数据已经转移走了，可以放心的覆盖。</p>
<p>所以Copy on Write实际上是让旧数据先占着位置，等新数据来了以后先把原来的数据复制走，再更新，而且一旦更新了一次，可以直接覆盖。</p>
<p><strong>带来的好处是 ，原卷上的数据随时是最新的状态，每个IO可以直接访问原卷的地址，而不需要遍历映射表。</strong></p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-a6e5df188123c7c9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h3 id="RoFW-方式与CoFW方式比较"><a href="#RoFW-方式与CoFW方式比较" class="headerlink" title="RoFW 方式与CoFW方式比较"></a>RoFW 方式与CoFW方式比较</h3><p>不管是RoFW还是CoFW,只要上层向<strong>快照后没有更新过的数据块</strong>进行写，都需要占用一个新的块。所以如果将所有扇区块都更新了，新卷的容量和原来的容量应该一样大，但是通常不会覆盖百分之百，所以只要预设原容量的30%即可。</p>
<p><strong>IO资源消耗：</strong></p>
<ul>
<li><p>CoFW方式下，如果要更新一个从未更新的块，需要复制出来，写到新卷，然后覆盖原来的块，需要：<strong>一次读，2写</strong>。</p>
</li>
<li><p>RoFW方式下，只需要一次写即可，也就是直接重定向到新卷上，然后更新映射图中的指针（在内存中进行）。</p>
</li>
</ul>
<blockquote>
<p>所以RoFW相对CoFW方式在IO资源消耗与IO延迟上有优势。</p>
</blockquote>
<p>由于只有首次覆盖才会Copy或者Redirect，那么如何<strong>区分是否是首次覆盖呢</strong>？可以使用记录表（文件级快照）或者位图（卷快照）来记录每个块是否被覆盖过。</p>
<p>对于<strong>读IO</strong>，</p>
<ul>
<li><p>CoFW：因为总是更新的源卷，所以源卷总是代表最新的状态，所以任何读IO都会发到源来执行</p>
</li>
<li><p>RoFW：需要首先查询位图来确定目标地址是否被处理过，如果是，则转向重定向后的地址。</p>
<p>  RoFW会影响<strong>读性能</strong>，因为重定向出去以后，数据块排布都是乱的，如果把快照删除后，不好清理战场，严重影响后续的读写性能。</p>
</li>
</ul>
<p>综合来说，RoFW比较吃计算资源，而CoFW比较耗费IO资源。</p>
<p>我们知道其实一般来说读比写多，<strong>当覆盖第二次</strong>以后</p>
<ul>
<li><p>CoFW不会发生IO惩罚，读IO一直没有惩罚</p>
</li>
<li><p>对于RoFW，就算完全被Redirect过了，对于读或者写IO，均需要遍历位图，永远无法摆脱对计算资源的消耗。</p>
</li>
</ul>
<p>尤其在LUN卷级快照下，原本卷在底层磁盘分布式是定死的，寻址非常迅速。但是RoFW引入了，LUN的块随机定向到其他的空间的，所以需要记录新的指针链，而且被写出的块不是连续排列的。对性能影响非常明显的。</p>
<p>绝大多数的厂商使用的还是<strong>CoFW</strong>，但是一些本来就使用LUN随机分块分布模式的存储系统比如XIV,NetApp等，都使用RoFW，因为原本其LUN的元数据链就很复杂，而且原来就是随机分布的，RoFW的后遗症对它们反而是正常的。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-0b62f79b708a89c1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h3 id="快照的意义"><a href="#快照的意义" class="headerlink" title="快照的意义"></a>快照的意义</h3><p>快照所保存下来的卷数据，相当于<strong>一次意外掉电之后卷上的数据</strong>。怎么理解?</p>
<p>上层应用和文件系统都有缓存，<strong>文件系统缓存的是文件系统的元数据和文件的实体数据。</strong>每隔一段时间（Linux一般是30s）批量Flush到磁盘上。而且不是只做一次IO，有可能会对磁盘做多次IO。如果快照生成的时间恰恰在这连续的IO之间，那么此时卷上的数据实际上有可能不一致。</p>
<p>文件系统的机制是先写入数据到磁盘，元数据保存在缓存里面，最后再写元数据。因为如果先写元数据，突然断电了，那么元数据对应的僵尸扇区的数据会被认为是文件的，显然后果不堪设想。</p>
<blockquote>
<p>总之，快照极可能生成不一致的数据。</p>
</blockquote>
<p><strong>那么为什么还要用快照呢？</strong></p>
<ul>
<li>因为快照可以任意生成，而且占用的空间又不大，更重要的是可以在线恢复，不用停机只需要在内存中做IO重定向，那么上层访问就变成以前时间点的数据了。</li>
</ul>
<p><strong>但是快照会存在不一致的问题，如何解决？</strong></p>
<p>既然快照无异于一次磁盘掉电，那么利用快照恢复数据之后，<strong>文件系统可以进行一致性检查</strong>，数据库也会利用日志来使数据文件处于一致。</p>
<p>另外，现在主流的快照解决方案是在主机上安装一个<code>代理</code>，<strong>执行快照前，先通知文件系统将缓存中的数据全部Flush到磁盘，然后立即生成快照。</strong></p>
<ul>
<li><p>快照还可以预防数据<strong>逻辑损坏</strong>，也就是比如T1时刻，做了快照，T2时刻，因为管理员操作不当，误删了一个文件，T3的时候，进行了全备份操作。此时，这个文件看似永久丢失了，其实，此时还可以通过快照恢复这个文件。</p>
</li>
<li><p>快照还可以降低一致性备份的窗口。如果没有快照，要对某个卷进行一致性备份，需要暂停写IO，所以<code>备份窗口</code>比较长，需要等待备份停止以后才能继续写IO。使用快照的话，只需要复制元数据，然后在后台进行备份，降低了影响。</p>
</li>
<li><p>备份完毕以后，如何能检测数据是否是真一致的？若没有快照，需要将备份数据恢复到独立的物理空间里面，挂载到另一台机器上。有了快照，可以将快照直接挂载到另一台主机，避免了数据物理恢复导入的过程。<br><img src="http://upload-images.jianshu.io/upload_images/1323506-4385052abbdc504d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
</li>
</ul>
<h2 id="卷Clone"><a href="#卷Clone" class="headerlink" title="卷Clone"></a>卷Clone</h2><p>快照类似于某时刻的影子，而克隆则是某时刻的实体。每时刻生成了一份可写的快照，就叫对卷某时刻的一份Clone。然后这份Clone内容每被修改的部分是与源卷共享的，所以源卷没了，则Clone就没了，所以叫<code>虚拟Clone</code></p>
<p>如果把数据复制出来，生成一个独立的卷，则就叫<code>Split Clone</code>，也就是可以得到<code>实Clone</code>。</p>
<p>卷Clone最大的好处在于可以瞬间生成针对某个卷可写的镜像，而不管卷的数据量有多大。</p>
<h1 id="数据备份系统的基本要件"><a href="#数据备份系统的基本要件" class="headerlink" title="数据备份系统的基本要件"></a>数据备份系统的基本要件</h1><ul>
<li>备份对象：需要进行备份的备份源。</li>
<li>备份目的：磁盘、磁带等介质</li>
<li>备份通路：网络</li>
<li>备份执行引擎：<strong>备份软件</strong></li>
<li>备份策略</li>
</ul>
<p>下面重点介绍一下备份目的、备份通路、备份引擎</p>
<h2 id="备份目的"><a href="#备份目的" class="headerlink" title="备份目的"></a>备份目的</h2><h3 id="备份到本地磁盘"><a href="#备份到本地磁盘" class="headerlink" title="备份到本地磁盘"></a>备份到本地磁盘</h3><p>备份目的地是在本地的磁盘，则只需要将数据备份到本地磁盘的另外分区中或者目录中。</p>
<p>这样不需要网络，缺点是对备份对象自己的性能影响大。还会对其他的IO密集型程序造成影响。</p>
<p>这种方式一般用于不关键的应用和非IO密集型应用。比如E-mail，对转发实时性要求不高。</p>
<h3 id="备份到SAN上的磁盘"><a href="#备份到SAN上的磁盘" class="headerlink" title="备份到SAN上的磁盘"></a>备份到SAN上的磁盘</h3><p>备份到SAN上的磁盘，就是将需要备份的数据，从本次磁盘读入内存，再写入HBA卡缓冲区，然后再通过线缆传送到磁盘阵列上。</p>
<ul>
<li><p>优点：只耗费SAN公用网络带宽，对主体影响小。</p>
</li>
<li><p>缺点：对公共网络资源和出口带宽有影响。</p>
</li>
</ul>
<h3 id="备份到NAS目录"><a href="#备份到NAS目录" class="headerlink" title="备份到NAS目录"></a>备份到NAS目录</h3><p>备份到NAS目录就是将数据备份到远程共享目录中。比如window中常用的文件夹共享。因为数据一般是通过以太网进行传递的，占用了前端的网络带宽，但是相对廉价，不需要部署SAN</p>
<h3 id="备份到磁带库"><a href="#备份到磁带库" class="headerlink" title="备份到磁带库"></a>备份到磁带库</h3><p>现在出现一种虚拟磁带库，即用磁盘来模拟磁带，对主机来说看到的是一台磁带库，实际上是一台磁盘阵列，主机照样使用磁带库一样来使用虚拟磁带库。要做到这点，就必须在磁盘阵列的控制器上做虚拟化操作，也就是实现协议转换器的作用。</p>
<p>可以带来了的好处是：</p>
<ul>
<li>速度提升</li>
<li>避免机械手这种复杂的机械装置</li>
<li>管理方便。</li>
</ul>
<h3 id="信息生命周期管理"><a href="#信息生命周期管理" class="headerlink" title="信息生命周期管理"></a>信息生命周期管理</h3><p>将使用不频繁的数据移动到低速、低成本的设备上。比如只给视频应用分配20GB的空间，但是报告有500GB的空间，剩下的空间是在在磁带库上。</p>
<h3 id="分级存储"><a href="#分级存储" class="headerlink" title="分级存储"></a>分级存储</h3><ol>
<li><p>一线磁盘阵列</p>
</li>
<li><p>二线虚拟磁带库：近期不会被频繁调度。利用大容量SATA盘，性能适中的控制器。</p>
</li>
<li><p>带库或者光盘库。几年甚至几十年都不访问到。<br><img src="http://upload-images.jianshu.io/upload_images/1323506-aa2e8744e3bad56e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
</li>
</ol>
<h2 id="备份通路"><a href="#备份通路" class="headerlink" title="备份通路"></a>备份通路</h2><h3 id="本地备份"><a href="#本地备份" class="headerlink" title="本地备份"></a>本地备份</h3><p><strong>数据流向</strong>：本地磁盘——总线——磁盘控制器——总线——内存——总线——磁盘控制器——总线——本地磁盘</p>
<p>也即数据从本地磁盘出发，经过本地的总线 和内存，经过CPU少量控制逻辑代码之后，流回本地磁盘。</p>
<h3 id="通过前端网络备份"><a href="#通过前端网络备份" class="headerlink" title="通过前端网络备份"></a>通过前端网络备份</h3><p>经过前端网络备份的数据流向是：<br>本地磁盘——总线——磁盘控制器——总线——内存——总线——以太网卡——网线——以太网——网线——目标计算机的网卡——总线——内存——总线——目标计算机的磁盘。</p>
<p><strong>数据从本地磁盘出发，流经本地总线和内存，然后流到本地网卡，通过网络传送到目标计算机磁盘。</strong></p>
<ul>
<li><p>前端网络：服务器接受客户端连接的网络，也就是<strong>服务网络</strong>，是服务器和客户端连接的必经之路。</p>
</li>
<li><p>后端网络：对客户封闭，客户的连接不用经过这个网络，用与服务器和存储、应用服务器、数据库服务器的连接。可以是SAN，以太网</p>
</li>
</ul>
<h3 id="通过后端网络备份"><a href="#通过后端网络备份" class="headerlink" title="通过后端网络备份"></a>通过后端网络备份</h3><p>通过后端网络备份的数据流向是：<br>本地磁盘——总线——控制器——总线——内存——总线——后端HBA卡——线缆——后端交换设备——线缆——备份目的的后端网卡——总线——内存——磁盘</p>
<h3 id="LAN-Free备份"><a href="#LAN-Free备份" class="headerlink" title="LAN Free备份"></a>LAN Free备份</h3><p>备份的时候不经过LAN，也就是不流经前端网络，也叫<code>Frontend Free</code>。这样的好处是<strong>不耗费前端网络的带宽，对客户终端接受服务器的数据不影响。</strong>。</p>
<p>因为前端网络一般是是慢速网络 ，资源非常珍贵。无论是本地、还是网络，都需要待备份的服务器付出代价，即需要读取备份源数据到自身的内存，然后从内存写入备份的目的地。对主机CPU、内存都有浪费。</p>
<p>能否不消耗服务器的性能呢？可以，使用Server Free备份。</p>
<h3 id="Server-Free备份"><a href="#Server-Free备份" class="headerlink" title="Server Free备份"></a>Server Free备份</h3><p> Server Free备份：备份的时候，数据不用流经服务器的总线和内存，消耗极少，甚至不消耗主机资源。</p>
<p>备份源和备份目标都不会在服务器上，因为如果在服务器上，数据从磁盘读出，要流将总线，然后到内存，这就不是<code>Server Free</code></p>
<p>那怎么做呢？</p>
<ul>
<li>用<code>SCSI</code>的扩展复制命令，将这些命令发送给支持<strong>Server Free的存储设备</strong>，然后这些设备会提取自身的数据写入备份目的设备，而不是发送给主机。</li>
<li>使用另一台专门做数据移动的<strong>新服务器</strong>，来代替原来服务器移动备份数据。释放运算压力很大的生产服务器。</li>
</ul>
<h2 id="备份策略"><a href="#备份策略" class="headerlink" title="备份策略"></a>备份策略</h2><blockquote>
<p>备份引擎：决定整个数据备份系统应该怎么运作，备份那些内容，什么时候开始备份，备份时间有没有限制等的策略。</p>
</blockquote>
<h3 id="备份服务器"><a href="#备份服务器" class="headerlink" title="备份服务器"></a>备份服务器</h3><p>备份引擎以什么形式体现呢？当然是运行在<strong>主机上的程序</strong>，所以需要一台计算机来做引擎的执行者。</p>
<p>那么备份服务器的备份策略和规则，怎么传给整个数据备份系统中的服务器？通过以太网，因为以太网扩展性好，适合节点间通信。相对于以太网，SAN更适合传送大量的数据。所以<strong>常用前端网络来连接待备份的服务器和备份服务器，因为备份策略的数据包不多。</strong></p>
<p>备份服务器如何与每个待备份的服务器建立通话？怎么通话？规则怎么定？需要待备份服务器上运行一个<strong>代理程序</strong>，专门解释备份服务器发来的命令，根据命令作出动作。</p>
<p>这个运行在待备份服务器上的程序，就叫<strong>备份代理</strong>，监听端口，接收备份服务器发来的命令。</p>
<h3 id="介质服务器"><a href="#介质服务器" class="headerlink" title="介质服务器"></a>介质服务器</h3><p>若数据备份系统中有一台SCSI磁带机，且多台主机想备份到这台磁带机上。而SCSI磁带机只能同时接到一台主机上。</p>
<p>那么怎么办呢？可以引入一台专门的计算机，只能由这台计算机来操作磁带机。<br>需要备份的计算机通过以太网将数据发给这台<strong>掌管磁带机的计算机</strong>，然后写给磁带机。</p>
<p>这样磁带机成为了公用设备，而在整个系统中，只有一台计算机能掌管备份目标，它就类似于一个<strong>代理</strong>，代理其他服务器执行备份。我们把它称为<code>介质服务器</code></p>
<p>还有一个问题，如果有多台服务器向<strong>介质服务器</strong>发出请求，怎么办?当然需要一个<code>协调员</code>，也就是<strong>备份服务器</strong>，它可以指挥安装在待备份服务器的<strong>代理</strong>，让每台服务器按照顺序有条理的使用<strong>介质服务器</strong>提供的备份介质进行备份。</p>
<h2 id="三种备份方式"><a href="#三种备份方式" class="headerlink" title="三种备份方式"></a>三种备份方式</h2><h3 id="完全备份"><a href="#完全备份" class="headerlink" title="完全备份"></a>完全备份</h3><p>不管文件多大，只要要备份，都需要将文件都备份下来。</p>
<h3 id="差量备份"><a href="#差量备份" class="headerlink" title="差量备份"></a>差量备份</h3><p>差量备份：只备份从上次完全备份以来发生<strong>变化</strong>的数据。</p>
<p>差量备份<strong>要求必须做一次完全备份，作为差量的基准点</strong></p>
<h3 id="增量备份"><a href="#增量备份" class="headerlink" title="增量备份"></a>增量备份</h3><p>只备份从上次备份以来这份文件中<strong>变化过</strong>的数据。** 上次备份**，不管是全备、差备，还是增量备份。</p>
<p>对于数据库的备份，备份软件想知道每个数据文件的变化是不可能的，因为数据库文件内部格式非常复杂，只有自己才能分析和检测出来。所以数据库管理软件有自己的备份工具。<strong>第三方备份软件只能调用数据库软件自身提供的命令。</strong><br><img src="http://upload-images.jianshu.io/upload_images/1323506-356bfab5550fb50a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

        
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="en">
    <link itemprop="mainEntityOfPage" href="https://duyang2903.gitee.io/2019/11/15/%E5%A4%A7%E8%AF%9D%E5%AD%98%E5%82%A8%EF%BC%8C%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%8811%E7%AB%A0%EF%BC%89%EF%BC%8CTCP-IP/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="dy2903">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="dy2903的博客">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          
            <a href="/2019/11/15/%E5%A4%A7%E8%AF%9D%E5%AD%98%E5%82%A8%EF%BC%8C%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%8811%E7%AB%A0%EF%BC%89%EF%BC%8CTCP-IP/" class="post-title-link" itemprop="url">大话存储，学习笔记（11章），TCP-IP</a>
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">Posted on</span>

              <time title="Created: 2019-11-15 10:48:24" itemprop="dateCreated datePublished" datetime="2019-11-15T10:48:24+08:00">2019-11-15</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">Edited on</span>
                <time title="Modified: 2019-11-13 21:27:13" itemprop="dateModified" datetime="2019-11-13T21:27:13+08:00">2019-11-13</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="TCP-IP协议"><a href="#TCP-IP协议" class="headerlink" title="TCP/IP协议"></a>TCP/IP协议</h1><p>以太网的出现，给系统的互联带来方便的方式，每个节点安装一块以太网适配器，上层程序只要将发送的数据以及目的MAC地址告诉以太网卡，就可以完成通信过程。</p>
<p>但是实际上，以太网不能直接被应用程序用来收发数据的，因为以太网是一个<strong>没有传输保障的网络。</strong></p>
<p>表现在：</p>
<ul>
<li>不会对数据帧进行校验纠错。</li>
<li>如果交换量大，可能会出现缓冲区队列满了的情况，所以以太网会主动丢弃，并且不会通知发送者。</li>
</ul>
<p>正因为如此 ，需要<strong>上层程序</strong>来获得可靠数据。</p>
<p>比如NetBEUI,NetBIOS,IPX,TCP/IP，这些协议其下层调用以太网提供的服务，上层对外提供新的调用接口。</p>
<p>而TCP/IP因为适用广，性能好，可以在超大规模的网络上运行，迅速得到普及。</p>
<h2 id="IP协议"><a href="#IP协议" class="headerlink" title="IP协议"></a>IP协议</h2><h3 id="作用一：屏蔽链路层地址"><a href="#作用一：屏蔽链路层地址" class="headerlink" title="作用一：屏蔽链路层地址"></a>作用一：屏蔽链路层地址</h3><p>以太网主要实现了OSI的下三层，即物理层、链路层、网络层，现在普遍认为以太网只作用到了链路层，这种误解的原因是以太网与TCP/IP结合就沦落为TCP/IP的链路层，其第三层地址被以太网IP所映射掉了。</p>
<p>而且以太网定义了MAC地址，也有自己的物理层，完全可以用来进行寻址。但是为什么没有完全靠MAC来寻址呢？因为</p>
<ul>
<li><p>首先MAC 太长，48bit，用于路由寻址的时效低。</p>
</li>
<li><p>最关键的是，世界上不是每个环境都用以太网来建立网络，还可以有其他的网络系统，有其他的寻址方式。</p>
</li>
</ul>
<p>比如以太网适合局域网通信，但是不适合广域网，一般来说广域网有专门的的联网协议，比如PPP , HDLC , FrameRelay ， X25 , ATM等，它们也如以太网一样各有各的寻址体系。</p>
<p>在一个Internet上有如此多的不同类型的网络，如果要联通，需要各种转换，映射。所以最好才解决方案是给他们通通分配一个IP地址给每个节点，对外以IP地址作为寻址地址，再将IP地址映射到所在网络的地址上，比如IP映射到Frame Relay 的DLCI ，映射到ATM的地址等。</p>
<p>以太网天生的弱点导致它必须向TCP/IP合作，而且只能将MAC地址隐藏，对外通通使用IP地址。</p>
<blockquote>
<p>总结一下，因为除了以太网以外，还有很多其他类型的联网方式，而几乎所有的联网方式都有自己的编址和寻址方式，为了兼容，<strong>只能将地址全都映射到IP地址上</strong></p>
</blockquote>
<p>既然有映射，当然需要一种协议来完成这个过程。那就是<strong>ARP协议</strong>，这个协议就是用来处理一种地址和另一种地址的映射。运行在每个网络设备上，将一种地址映射成<strong>底层网络设备</strong>所使用的另一种地址。</p>
<p>每种网络要想用IP来统一就必须运行各自的ARP协议，比如以太网的ARP ， 帧中继的ARP。</p>
<blockquote>
<p>ARP协议：主要用来将IP地址映射到底层设备的地址（MAC地址）</p>
</blockquote>
<p>我们以浏览器中输入网络域名之后发生的事情来举例。</p>
<ul>
<li><p>首先DNS兑换程序自动向DNS服务器查询，获得域名对应的地址，然后用IP地址与服务器通信。</p>
</li>
<li><p>数据包带着IP地址到了服务器所在的局域网，会通过局域网的路由器发出的ARP请求，将IP地址兑换为服务器所在局域网的地址，</p>
</li>
<li><p>如果服务器所在的局域网是以太网，则对应成MAC地址，然后通过以太网交换设备，找到此MAC地址所在的交换机端口，将数据包发向这个端口。</p>
</li>
</ul>
<p>上述过程发生了两种不同的兑换：</p>
<ul>
<li><p>IP转换为域名，这是因为IP不方便记忆，所以我们平时使用类似”<a href="http://www.baid.com&quot;这样的字符来表示网站，当然需要在后台将域名和IP进行相互转换。" target="_blank" rel="noopener">www.baid.com&quot;这样的字符来表示网站，当然需要在后台将域名和IP进行相互转换。</a></p>
</li>
<li><p>MAC转换IP：为了统一。</p>
</li>
</ul>
<h3 id="作用二：适配上下层"><a href="#作用二：适配上下层" class="headerlink" title="作用二：适配上下层"></a>作用二：适配上下层</h3><p>IP层另外的作用是适配上下层：给链路层和传输层提供适配。</p>
<blockquote>
<p>链路层有MTU的概念：链路的最大传输单元，即每帧所允许的最大字节数。</p>
</blockquote>
<p><strong>链路层</strong>就类似司机和交通规则，对货车的载重、大小有要求，如果货物太大，就必须分割。这个动作是由<strong>IP层程序</strong>来做，也就是IP根据链路的MTU来分割货物，然后贴上源目的IP地址、顺序号。</p>
<p>路由器每次选择的路径不一样，所以到达目的地以后可能乱序了，此时可以使用<strong>顺序号</strong>。这个顺序号是根据分割处相对起点的距离，根据这个号，等所有货物到达了以后，对方的IP程序可以将这个号码组装起来。</p>
<blockquote>
<p>每个货物块都携带IP头，但是只有第一块携带TCP头部 。因为传输层头部是在应用数据之前的，所以IP在分割的时候，一定会把头部分到第一块中。</p>
</blockquote>
<h3 id="缺点"><a href="#缺点" class="headerlink" title="缺点"></a>缺点</h3><p>IP最大的作用是寻址和路由，以及<strong>适配链路层的MTU</strong>。但是以太网是个<strong>面向无连接</strong>的网络， 不保障数据一定会传送到对方。</p>
<p>Frame Relay协议，其前身X.25协议，有很好的传输保障功能，因为其设计初衷是为了运行在不稳定的链路，当链路的质量不断提升，x25的做法有些多余，所以在FR替代了X25，只留下流控机制。</p>
<p>但是以太网和FR都没有实现端到端的传输保障。端到端是相对于“过路”而言的。过路是指在两个终端之间通信路径上的网络设备之间的路径。链路层只保障两个设备之间传送的数据无误，但是不能保证最终终端传输的无误。</p>
<h2 id="TCP和UDP"><a href="#TCP和UDP" class="headerlink" title="TCP和UDP"></a>TCP和UDP</h2><p>TCP/IP协议包含两个亚层：</p>
<ul>
<li>IP：统一底层网络地址和寻址</li>
<li>TCP或者UDP：逻辑上位于IP上。</li>
</ul>
<p>TCP和UDP的功能</p>
<ul>
<li><p>TCP功能：维护复杂的状态机，保障发送方发出的数据包都会传送到接收方。出错的话，则反馈信息。</p>
</li>
<li><p>UDP功能：TCP/IP对以太网的透传。没有传输保障功能的亚层。除了UDP可以提供比以太网更方便的调用方式，其他没有本质区别。</p>
</li>
</ul>
<p>TCP/IP协议向应用程序呈现的接口就是Socket接口，即插座接口。TCP/IP想让应用程序更方便的使用网络，就像插头插入插座一样。</p>
<p>基于TCP/IP的应用程序，必须依赖于TCP/IP协议，如Ping , Trace , SNMP,Telnet , SMTP,FTP,HTTP</p>
<p>这些协议加上IP、TCP等，然后加上物理层链路层（以太网等），形成了TCP/IP协议簇。</p>
<p>所以说TCP运行在终端上，监控终端最终发送的接收的数据包的顺序、缓存区、校验。<br><img src="http://upload-images.jianshu.io/upload_images/1323506-39ac16c5bd7103c7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h3 id="TCP协议"><a href="#TCP协议" class="headerlink" title="TCP协议"></a>TCP协议</h3><p>TCP就是个押运员，是由它把货物交给IP做调度的。</p>
<p>货物最初是由应用程序生成，调用Socket接口向接收方发送货物。通告TCP/IP去特定的内存区将数据复制到Socket缓冲区，然后TCP再从缓冲区将数据通过IP层分片之后，从底层网络适配器发送到对端。</p>
<p>TCP通过MSS（max Segment Size）来调整每次转给IP层的数据大小。而MSS值完全取决底层链路的MTU。</p>
<p>为了避免IP分片，MSS总等于MTU值减掉IP头，再减掉TCP头的值，TCP发送给IP的数据，IP加上IP头之后，恰好等于底层链路的MTU值，使得IP不需要分片。</p>
<p><strong>TCP将上层应用的数据完全当成字节流</strong>，不进行定界处理,认为上层应用数据就是一连串的字节，不认识字节的具体含义，却可以分割这些字节，封装成货物进行传送，但是必须保证数据排列顺序。</p>
<blockquote>
<p>TCP将上层数据“分段” ， IP将TCP分段再“分片”（若此段大于MTU）<br>IP到达目的地以后，会将分片合并为分端，然后放到货仓，顺序排放，<strong>不管上层消息的分界</strong>。</p>
</blockquote>
<h3 id="UDP协议"><a href="#UDP协议" class="headerlink" title="UDP协议"></a>UDP协议</h3><p>UDP只是被动的起到了一个IP和上三层的接口的作用。</p>
<p>没有出错重传，没有缓冲、定时器、状态机，而且也不会像TCP将数据流分段，适配MTU的工作完全由IP来做。</p>
<p>没有握手机制，所以UDP头部只有8个字节长，包括目的和源端口号，UDP数据包长度、UDP校验和，效率高。所以UDP协议一般用于实时性高的地方，比如<strong>视频流</strong></p>
<h3 id="端口号"><a href="#端口号" class="headerlink" title="端口号"></a>端口号</h3><blockquote>
<p>OS上运行N个程序，如果需要通信，可以使用号码来标识，所以只要知道了进程号就可以区分程序。</p>
</blockquote>
<p>同一PC上的程序通信，一般是在内存中直接通信，但是如果两台计算机的两个程序都需要通信，若用内存共享，成本太高，所以可以采用先发送到另一台计算机，然后让接收消息的计算机将这个消息发送给对应的程序。</p>
<p>所以接收方的OS中的TCP/IP协议必须知道某个数据包应该放到哪一个应用程序的缓冲区，因为同一时刻可能有多个应用调用Socket 进行数据收发。</p>
<p>为了区分正在调用Socket的不同应用程序，规定了<strong>端口号</strong>。</p>
<p>所以在调用socket的时候，必须声明连接目的计算机TCP/IP协议的那个端口号。</p>
<h2 id="TCP-IP与以太网的关系"><a href="#TCP-IP与以太网的关系" class="headerlink" title="TCP/IP与以太网的关系"></a>TCP/IP与以太网的关系</h2><p>有人把TCP/IP与以太网等同起来，是完全错误的。</p>
<p>TCP/IP与以太网是互相利用，而非相互依存。</p>
<p><strong>TCP/IP协议不像以太网有底层专门的硬件</strong>，绝对是可以租用一切合适的硬件来作为物理和链路层。</p>
<p>比如TCP/IP可以用无线、USB、COM串口、ATM作为物理层和链路层。</p>
<p>以太网有自己的网络层编址和寻址，有网络层的元素</p>
<p>TCP/IP在网络层和传输层的功能应用太广泛了，所以OSI的第三和第4层几乎是被TCP/IP统治了。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-382ad72428055919.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

        
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="en">
    <link itemprop="mainEntityOfPage" href="https://duyang2903.gitee.io/2019/11/15/%E5%A4%A7%E8%AF%9D%E5%AD%98%E5%82%A8%EF%BC%8C%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%8815%E7%AB%A0%EF%BC%89%EF%BC%8C%E6%96%87%E4%BB%B6%E7%BA%A7%E9%9B%86%E7%BE%A4%E7%B3%BB%E7%BB%9F/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="dy2903">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="dy2903的博客">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          
            <a href="/2019/11/15/%E5%A4%A7%E8%AF%9D%E5%AD%98%E5%82%A8%EF%BC%8C%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%8815%E7%AB%A0%EF%BC%89%EF%BC%8C%E6%96%87%E4%BB%B6%E7%BA%A7%E9%9B%86%E7%BE%A4%E7%B3%BB%E7%BB%9F/" class="post-title-link" itemprop="url">大话存储，学习笔记（15章），文件级集群系统</a>
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">Posted on</span>

              <time title="Created: 2019-11-15 10:48:24" itemprop="dateCreated datePublished" datetime="2019-11-15T10:48:24+08:00">2019-11-15</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">Edited on</span>
                <time title="Modified: 2019-11-13 21:27:14" itemprop="dateModified" datetime="2019-11-13T21:27:14+08:00">2019-11-13</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p><a href="https://www.jianshu.com/p/2f8ede83b183" target="_blank" rel="noopener">【大话存储II】学习笔记（15章），块级集群存储系统</a>里面分析的主要是块集群系统，同样文件级存储也可以集群化。</p>
<p>因为NAS系统的前端网络是以太网，速度比较低，导致NAS主要用于一些非关键业务中，比如文件共享。但是一些特殊应用也需要多主机同时访问某个大文件，比如3D渲染集群等。如果我们使用块集群存储系统，则会存在一个问题，需要在应用程序上引入<strong>文件锁</strong>，而NAS的文件系统一般都自带有文件锁机制，所以还不如把NAS存储系统进行集群化。</p>
<p>在谈怎么样把NAS系统进行集群化之前，我们说说<strong>集群文件系统</strong>的架构。集群文件系统是个很宽泛的概念，分布式文件系统、并行文件系统、共享文件系统统都可以称为<code>集群文件系统</code>。</p>
<h1 id="集群文件系统"><a href="#集群文件系统" class="headerlink" title="集群文件系统"></a>集群文件系统</h1><p>集群文件系统，顾名思义，就是把提供文件存储的设备进行集群化。一般来说，我们可以使用一堆服务器来提供文件服务。</p>
<p>本章中，我们首先对集群文件系统架构进行分类，主要有如下几种</p>
<ul>
<li><p>共享与非共享存储型集群</p>
</li>
<li><p>对称与非对称集群</p>
</li>
<li><p>自助型与服务型集群</p>
</li>
<li><p>SPI与SFI型集群</p>
</li>
<li><p>串行与并行集群</p>
</li>
</ul>
<h2 id="是否共享LUN"><a href="#是否共享LUN" class="headerlink" title="是否共享LUN"></a>是否共享LUN</h2><p>我们可以按照集群是否有共享LUN将架构分为共享存储集群和非共享存储集群</p>
<ul>
<li><p>共享存储集群</p>
<p>  集群的所有节点都是共享使用后端存储的，注意这里的共享不是说共享磁盘阵列，而是说可以<strong>共享访问同一个LUN。</strong><br><img src="http://upload-images.jianshu.io/upload_images/1323506-41e97a152f2ddbc3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"><br>  这就引出另一个问题了，多主机同时读写同一个LUN里面的文件，<strong>如何保证数据一致性？</strong></p>
<p>  无法保证数据一致性的原因在于存在多个独立的文件系统逻辑，每个客户端都要维护自己的文件系统缓存，而且它们之间不互相通信。</p>
<p>  我们可以直接把多余的文件系统实例去除掉，只保留一份文件系统逻辑，这就形成了共享式SAN文件系统了。</p>
<p>  下图为传统的架构。多个主机共同访问一个LUN的文件，会产生数据不一致。因为主机各自为政，任意一台客户端要访问目标文件的时候，会向自身内存中的文件系统发起请求，从而执行IO。<br><img src="http://upload-images.jianshu.io/upload_images/1323506-62c18f207bc60d7e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"><br>  下图是进化后的架构，只需要有一个客户端主机上保留一份文件系统，也就是<strong>元数据服务器</strong>。所以客户端要访问文件的时候，需要先通过网络向元数据服务器发出请求，然后自行向目标发起访问。</p>
</li>
</ul>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-33c4e044349bfd9e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<ul>
<li><p>非共享存储集群</p>
<p>  与共享存储集群相反则是非共享存储集群，每个节点都独占一个LUN。当然集群也可以使用同一台磁盘阵列，但是各自的存储空间是之前划分好的，只能自己访问，别人不能访问。<br><img src="http://upload-images.jianshu.io/upload_images/1323506-d751f906c172fada.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
</li>
</ul>
<p>同样我们也可以单独剥离出<strong>元数据服务器</strong>，然后把后端主机并行化。<br>这样的好处在于，客户端从存储节点读取数据的时候，完全可以<strong>并行访问</strong>。可以大大提升访问效率。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-0f0fd95485e57019.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"><br>共享与非共享存储集群对比如下：</p>
<ul>
<li><p>读写数据的过程：当某节点需要访问其他节点上的数据的时候，</p>
<ul>
<li><p>共享存储集群：每个节点可以直接对后端存储中的LUN进行读写，前端传输的只有元数据，而没有实际数据流量。</p>
</li>
<li><p>非共享存储的集群文件系统：如果要访问非当前节点的数据，需要通过前端网络进行传输，速度较慢。</p>
</li>
</ul>
</li>
</ul>
<ul>
<li><p>缓存一致性：共享存储需要考虑缓存一致性，一般来说需要把写缓存给关了，非共享式不需要考虑。</p>
</li>
<li><p>某节点故障以后：共享存储，一个节点故障，另外的节点可以直接接管。非共享存储，为了防止单点故障，需要将每个节点的数据镜像一份到其他节点。</p>
</li>
<li><p>是否需要使用SAN阵列：共享存储必须使用SAN阵列，非共享式集群可以不使用SAN阵列，服务器节点的本地槽位多的话，可以使用本地磁盘，但是不可使用DAS磁盘箱。</p>
</li>
</ul>
<p><code>非共享存储型文件系统</code>又可称为“<code>分布式文件系统</code>”，即数据分布存放在集群中多个节点上。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-bbc2b6152b74dba4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h2 id="是否引入IO节点"><a href="#是否引入IO节点" class="headerlink" title="是否引入IO节点"></a>是否引入IO节点</h2><p>上一小节中讲的架构中，客户端可以直接访问到共享存储。</p>
<p>实际上可以在插入一个中间层，可以对后端文件以另一种形式进行输出。</p>
<p>比如</p>
<ul>
<li><p>比如在LUN上层引入了对象存储网关，则就是对象存储。</p>
<p>  需要客户端需要使用支持OSD协议的代理，比如pNFS</p>
</li>
<li><p>如果引入了私有设备，则需要使用相应的代理。</p>
</li>
<li><p>如果引入了NAS头，则形成了集群NAS，对外只需要使用标准的NFS客户端即可。</p>
<p>  典型代表是：Panasas , Lustre , Ibrix</p>
</li>
</ul>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-18f18d67b848209d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>终上所述，集群文件系统最后演化成了两种：</p>
<ul>
<li><p>客户端直接访问后端SAN</p>
</li>
<li><p>客户端和后端FC SAN 之间引入IO节点的模式</p>
</li>
</ul>
<p>这两种方式各有其优劣</p>
<ul>
<li><p>客户端直接访问SAN的模式，客户端与后端的磁盘阵列没有其他的处理模块，IO效率最高。</p>
<p>  但是成本随着客户端的增加而增加，因为目前FC HBA卡非常贵，如果每个客户端安装FC HBA卡，成本将非常高。此外，因为后端LUN都由元数据服务器来挂载，存在单点故障，一旦元数据服务器出问题了，则系统就瘫痪</p>
</li>
<li><p>客户端与SAN之间引入了IO节点的模式：</p>
<p>  客户端可以使用便宜一点的<code>以太网</code>来进行IO节点的访问，另一方面如Ibrix这样所有节点的角色对等的架构，每个节点都是MDS和IO节点，这样的话，一旦某个IO节点故障，则其他任何一个IO节点就可以接管故障节点的资源，容错率高了很多。</p>
<p>  当然有利必有弊，IO效率相对就比较低了，而且受以太网速率的限制，客户端IO速度也不高。</p>
</li>
</ul>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-bef4f51847587ea8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h2 id="角色是否对等"><a href="#角色是否对等" class="headerlink" title="角色是否对等"></a>角色是否对等</h2><p>可以根据每个节点的角色是否对等分为对称式和非对称式文件系统。</p>
<p> 所谓<strong>对称式集群文件系统</strong>指的是集群中所有节点的角色和任务都相同，完全等价。</p>
<p>在对称式集群中，所有节点都很<code>聪明</code>，每时每刻都能保持精确沟通与合作，共同掌管全局文件系统的元数据。每个节点要更新某元数据的时候，需要先将其<strong>锁住</strong>，其他节点就必须等待，<strong>这样节点之间的沟通量就很大。</strong></p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-883578512edab3d3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>所有节点在同一时刻均看到同一片景像。</p>
<p>那么<strong>非对称式集群</strong>呢？</p>
<p>在非对称集群中，只有少数节点（主备节点）是聪明的，他们掌管着系统内全局文件系统信息，其他节点不清楚。</p>
<p>当其他节点要访问某文件的时候，需要首先联系这个聪明节点，得到要访问文件的具体信息（比如存放在哪个节点中的哪的LUN的什么地址里面。）</p>
<p>每个傻节点上需要安装一个<code>代理</code>客户端来于聪明节点通信，它获得了文件的具体信息之后，才能让主机从后端的LUN中拉取数据。</p>
<p>我们把<code>聪明</code>的节点叫<code>Metadata Server, MDS或者MDC</code>，是系统中唯一掌握文件系统元数据的角色。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-38e82c4c49a75ae6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>那么对称集群文件系统与非对称的典型代表是哪些？</p>
<ul>
<li><p>对称式集群：Veritas ClusterFS , HP Ibrix</p>
</li>
<li><p>非对称式集群：中科蓝鲸BWFS，EMC MPFS</p>
</li>
</ul>
<p>显然这两种架构各有优劣势。</p>
<ul>
<li><p>非对称式集群易于实现，沟通成本低，对应的产品也多。</p>
<p>  客户端只能通过元数据服务器进行挂载，所以性能受限于元数据服务器，不过我们可以引入多个元数据节点来均摊负载。</p>
</li>
<li><p>对称式集群文件系统：因为所有节点的地位相同，所以挂载任何一个节点的目录即可，但是节点之间构成的复杂度高，不利于扩展。</p>
<p>  当节点少的时候，由于对称式集群中每个节点都可以充当<strong>元数据服务器</strong>的角色，所以性能更好。</p>
</li>
</ul>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-f2756c4b557e96f4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h2 id="是否对外提供服务"><a href="#是否对外提供服务" class="headerlink" title="是否对外提供服务"></a>是否对外提供服务</h2><p>按照是否对外提供服务分为自助型和服务型</p>
<p>什么叫<strong>自助型集群</strong>？就是应用是使用本地磁盘的，比如一个集群中每个节点都安装了某种应用，然后现在有共享系统内所有文件的需求，就可以在<strong>应用节点上</strong>直接部署集群文件系统。</p>
<p>所以每个节点不但是数据的生产者，还是底层文件的消费者,这就是<code>自助型</code></p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-7c2b48b40d637039.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>那什么是<code>服务型集群文件系统</code>，如下图。</p>
<p>框内是集群文件系统，框外又增加了一排主机，群外的客户端主机通过某种协议来访问集群中文件数据。</p>
<p>集群中的服务节点不是数据的消费者，只是服务者</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-0e7504381907bb9b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>为什么要使用服务型集群呢？自助型不是挺好的吗？主要原因如下</p>
<ul>
<li><p>降低成本。自助型集群中每个节点都需要高速网卡，比如FC HBA卡，集群规模扩大，则成本也会扩大。</p>
</li>
<li><p>可以接入更多的客户端</p>
<p>  可以用较少的节点服务于更多的客户端主机。而且内部沟通信息量更小。<br><img src="http://upload-images.jianshu.io/upload_images/1323506-f11d7b9e5e11a37f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
</li>
</ul>
<h2 id="统一路径型与统一文件系统型集群"><a href="#统一路径型与统一文件系统型集群" class="headerlink" title="统一路径型与统一文件系统型集群"></a>统一路径型与统一文件系统型集群</h2><p>之前我们讲过，为了实现集群的<code>Single Name Space</code>统一命名空间，有两种方式</p>
<ul>
<li>懒人做法：既然每个节点都有各自的文件系统，那么就直接把输出路径虚拟化一下，集中管理起来就OK。再向外输出一个Single Path Image。只管路径统一，放在那里不管。典型代表就是微软的DFS</li>
</ul>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-b97ca150bd720d86.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<ul>
<li>勤快人做法：让每个节点都知道所有文件的位置，在文件系统层进行整合而不只是在表层路径上进行整合，即Single FileSystem Image。典型代表，CFS等大多数集群FS。</li>
</ul>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-26acfccdf419e937.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>SFI的优点在于可以将一个文件切分到各个节点中，这是SPI无法做到。</p>
<p>但是SFI的扩展性能往往比较有限，SPI则可以整合大量的节点。这是因为SFI的集群FS的节点之间需要同步复杂的状态，每个节点所维护的状态机非常复杂，当节点数量增加的时候，<strong>节点状态机</strong>的协同加上<strong>网络延迟</strong>，性能自然上不去。<br>而SPI模式下，节点相互独立，同步的信息很少。。</p>
<h2 id="串行与并行集群"><a href="#串行与并行集群" class="headerlink" title="串行与并行集群"></a>串行与并行集群</h2><p>对于<strong>服务型集群</strong>，可以提供两种方式的对外访问：</p>
<ul>
<li><p>串行的方式：挂载集群中的某个节点的目录，然后所有的通信都通过这个节点执行。</p>
</li>
<li><p>并行访问：</p>
<p>  客户端最开始会挂载在某个节点上，但是只是通过这个节点获取元数据信息，客户端可以并行的访问从多个节点中读写数据。</p>
<ul>
<li>对称模式下的并行<br><img src="http://upload-images.jianshu.io/upload_images/1323506-3da128de25e8c0a9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></li>
<li>非对称模式下的并行<br><img src="http://upload-images.jianshu.io/upload_images/1323506-3cfad636b406130f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></li>
</ul>
</li>
</ul>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-2181a3bba971673c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h1 id="集群文件系统中的关键问题"><a href="#集群文件系统中的关键问题" class="headerlink" title="集群文件系统中的关键问题"></a>集群文件系统中的关键问题</h1><p>集群本质是一堆服务器合作处理任务，这一点集群块存储系统与集群文件存储系统没有区别。但是当我们面对的不是单一节点以后，会多出很多的问题， 比如说能不能用统一的目录对后端的文件进行访问，比如说多主机对某个文件访问的时候会不会有冲突，还有就是每台设备都会缓存数据，会不会有缓存不一致的情况。</p>
<p>下面我们将一一讲解</p>
<h2 id="统一命名空间（Single-Name-Space）"><a href="#统一命名空间（Single-Name-Space）" class="headerlink" title="统一命名空间（Single Name Space）"></a>统一命名空间（Single Name Space）</h2><p>如果我们要访问某个文件，则需要知道文件的路径，也就是说文件是在哪个目录里面，比如windows下面的路径”D:\data\file.txt”，或者Linux下面的”/usr/someone/file.txt”。windows和Linux文件系统的设计方式不同，所以路径看上去也不同。</p>
<ul>
<li><p>Windows默认为以各个分区做为入口，所以路径开始会指明是在那个<strong>分区</strong>里面。</p>
</li>
<li><p>而Linux是以全局为入口，所以开头是根目录”/“，而各个分区都<code>挂载</code>到某个目录下，比如分区sda2挂载到<code>/home/mnt</code>下面。那么如果我们进入到<code>/home/mnt</code>，其实就相当于进入了sda2分区文件系统的根入口。同理Windows也可以把<strong>分区</strong>挂载到某个目录下。</p>
</li>
</ul>
<p>如果我们把一个目录挂载到另一个目录下面，这个<strong>被挂载</strong>的目录就可以称为<code>虚拟目录</code>。也就是说通过虚拟目录访问到的不是原本属于此目录下的文件，而是挂载在其上的目录树。</p>
<p>所以虚拟目录更应该理解为<strong>一个路径</strong>，它只是提供一个路牌，路牌上的路名不等于路的本身，只是一个名字而已。</p>
<p>现在我们来看一个集群环境下的情况。</p>
<p>每个节点都有各自的<code>路径</code>，但是既然多节点组成了集群，对外应该呈现为一套路径。</p>
<p>比如说客户端看到路径<code>/cluster/data1</code>，而这个路径真实应该在节点A上。不管向集群中哪个节点发出请求，所有的请求都应该重定向到节点A来，收到请求的节点就相当于一个<strong>代理</strong>而已。也就是说已经被某节点使用的路径，不能再被其他节点所使用了。</p>
<p>这就是统一命名空间（Single Name Space）：集群中的所有节点上供客户端挂载的路径不重复，对外呈现为单一的NAS服务器。</p>
<p>这就是与非集群环境下最大区别。非集群下，两台NAS设备有同一个路径，而且对外可见，那么客户端可以挂在两个不同的独立存储空间，这样当然管理起来很麻烦。</p>
<p><strong>那么怎么实现统一命名空间呢</strong>？有两种形式</p>
<ul>
<li><p>单一路径影像（Single Path Image）：</p>
<p>  节点只需要管理自己的文件系统空间，然后在上面加一个<strong>中间层</strong>，可以把多个文件系统虚拟为同一个空间。比如/a和/b虚拟化为一个/c，这种方式就是单一路径镜像。</p>
<p>  这种方式下，每个节点其实只能看到自己节点上的路径，如果收到了访问其他节点目录的请求，应该将请求<strong>重定向</strong>到另外的节点上，当然处理的结果还是由收到请求的节点返回给客户端，这样做的目的是保证对客户端的透明。</p>
</li>
<li><p>单一文件系统影像（Single FileSystem Image）</p>
<p>  单一路径影像只是在路径上进行了一层虚拟化，所以可以对外呈现出单一的虚拟目录。而单一文件系统影像更彻底，它想将所有节点的文件系统进行融合，所以它会在本地文件系统（如EXT3）上加了一层虚拟化逻辑，这样就改变本地文件系统的逻辑，比如可以这样，客户端看来，某个文件在/fs/a上面，但是实际上有可能前半端在节点A，后半段在节点B。</p>
<p>因为文件系统已经<strong>“彻底”</strong>融合了，所以集群中的每个节点都知道所有文件的存放位置和状态，所以这种模式下，收到客户端IO请求的<strong>节点</strong>会对IO进行解析，然后就知道数据应该落到哪些节点上，最后把IO拆分后发到对应的集群节点上进行读取或者写入。而不是像单一路径影像那样将请求重定向到其他节点上。</p>
</li>
</ul>
<p>总之单一路径影像属于松耦合，更利于节点的扩充。而单一文件系统影像是把文件系统都融合了起来，属于紧耦合，扩展性不好，实现难度大。</p>
<h2 id="集群中的分布式锁机制"><a href="#集群中的分布式锁机制" class="headerlink" title="集群中的分布式锁机制"></a>集群中的分布式锁机制</h2><p>在单节点的的单一操作系统内，可能有多个应用程序对同一个文件进行修改，这样极有可能出现数据不一致的情况，于是我们引入了<code>锁</code>，这样一个文件在同一时刻只允许这个应用程序修改，其他应用程序只能等待。</p>
<p>这样又会出现一个问题，若干某个文件加锁了，却迟迟未被处理，其他应用程序就只能等待，时间自然就白白浪费了。</p>
<p>锁也不是，不锁也不是，那么有没有两全其美的方法呢？</p>
<p>当然有，比如</p>
<ul>
<li><p>字节锁：</p>
<p>  程序只是把某端或者某些字节加锁了，所以多个程序可以并行的读写文件的不同部分。这样锁的粒度就降低了，可以并行的读写同一文件，性能自然得到提高。</p>
</li>
<li><p>集群中的分布式锁</p>
<p>  集群其实可以看作一台大的独立系统，集群外的客户端相当于应用程序，因为有并行，自然也需要锁。</p>
<p>  但是集群是由多个节点组成的，维护锁需要由哪些节点负责呢？一般有两种方式</p>
<ul>
<li><p>集群中所有节点选一个节点负责锁的维护，这就是<code>集中式锁管理</code>，用于非对称式集群</p>
</li>
<li><p>所有节点共同维护锁，锁的信息在节点上同步，这就是<code>分布式锁管理</code>，用于对称式集群。</p>
</li>
</ul>
</li>
<li><p>元数据锁</p>
<p>  如果一个集群中，所有的节点的角色对等，而且共享存储，那么此时所有的节点掌握着文件系统元数据，而且是实时同步的。</p>
<p>  那么当节点要为某个文件分配空间的时候，需要把<strong>相关的元数据</strong>锁住。为什么呢？因为如果不锁住，如果此时其他节点也在分配空间，则两个节点分配的空间可能有冲突。</p>
<p>  那么当一个节点要分配数据了，可以利用<strong>分布式锁机制</strong>通知其他节点，位图已经由它掌控了。当然分配完成之后，还要再与其他节点同步一下自己的元数据缓存。</p>
</li>
</ul>
<h2 id="缓存一致性"><a href="#缓存一致性" class="headerlink" title="缓存一致性"></a>缓存一致性</h2><p>我们知道集群的节点会维护一个<strong>读缓存</strong>，所以一个节点有可能缓存其他节点的某些内容。那么就存在一种情况，某一时刻节点存储的内容被应用<code>修改</code>了，但是这段内容的读缓存有可能在其他的节点上，如果此时有终端读到了缓存里面的内容，则出现与实际数据不一致的情况。</p>
<p>那么怎么办？可以把<strong>读缓存的数据作废或者读入新数据以更新</strong>,这就是<code>写即作废</code>机制，可以保证全局缓存一致性。</p>
<p>那写缓存呢？</p>
<ul>
<li><p>对于有<strong>共享存储</strong>的集群，</p>
<p>  最好不开写缓存，也就是写入的时候最好要直接写到磁盘上再返回成功，就好比公用物品必须放回原处，别人才能继续用，而不能只是放到自己的缓存。</p>
<p>  如果实在要使用写缓存也可以，当写的数据放到了缓存里面以后，需要立刻通知到集群中其他节点。那么其他节点要对这段数据进行操作的话，需要与此节点进行联系。不过这就需要花费沟通成本来保证缓存一致性了。</p>
</li>
<li><p>如果集群没有共享存储</p>
<p>  写入的数据都缓存在本节点中，其他节点要访问数据的话，必须联系数据的拥有者，不存在不一致的问题。</p>
</li>
<li><p>如果集群文件系统是对外提供服务的，那么写缓存最好关闭，因为集群节点没有类似SAN磁盘阵列的掉电保护机制，一旦掉电，则数据丢失。</p>
</li>
</ul>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-24f7ab844b784e37.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h1 id="集群、并行、分布式、共享文件系统辨析"><a href="#集群、并行、分布式、共享文件系统辨析" class="headerlink" title="集群、并行、分布式、共享文件系统辨析"></a>集群、并行、分布式、共享文件系统辨析</h1><p>大家平时可能听到多种叫法：集群文件系统、SAN共享文件系统、分布式文件系统、并行文件系统。这些概念之间是否有什么联系呢？</p>
<ul>
<li><p>SAN共享文件系统：指的是共享存储集群文件系统。又可简称为<code>SAN文件系统</code></p>
</li>
<li><p>分布式文件系统：可以等价于<code>非共享存储</code>集群文件系统，也就是说同一个文件系统下的文件是存放在不同的节点里面</p>
</li>
<li><p>并行文件系统：可以提供<code>并行</code>访问的集群文件系统，一般需要在主机客户端上安装一个<code>代理</code>或者新的文件系统挂载器，专门实现并行访问。</p>
<p>  分布式不一定代表着并行，但是并行一定是分布的。并行文件系统</p>
</li>
<li><p>集群文件系统：分布式文件系统、并行文件系统、共享文件系统统称为<code>集群文件系统</code>。</p>
<p>  <code>分布式</code>和<code>共享式</code>指的是数据分布的方式，而<code>并行</code>指的是用户对数据的访问方式。</p>
</li>
</ul>
<h1 id="集群NAS"><a href="#集群NAS" class="headerlink" title="集群NAS"></a>集群NAS</h1><p>在<a href="https://www.jianshu.com/p/469c27b6cf3b" target="_blank" rel="noopener">【大话存储】学习笔记（10~13章），NAS、IP SAN</a>这一章中，我们讲到了NFS/CIFS协议，它们是<strong>网络文件访问系统</strong>，主要的作用是让主机可以通过网络的访问NFS服务器上的文件，所以它其实不是管理文件与扇区的对应关系的。</p>
<p>而FAT、NTFS是实实在在的文件系统，是管理文件与块的对应关系的，我们称为<strong>文件管理系统</strong></p>
<p>那么现在我们要构建一个集群NAS，希望他能对外提供文件访问服务。</p>
<ul>
<li><p>最底层仍然使用NTFS、EXT3等文件管理系统，主要来管理文件与块的对应关系，</p>
</li>
<li><p>然后在上面增加一层集群文件系统，主要用来管理集群的元数据信息</p>
</li>
<li><p>再包裹一层NFS就可以对外提供文件服务了，形成了分布式并行文件系统。</p>
</li>
</ul>
<p>如下图所示<br><img src="http://upload-images.jianshu.io/upload_images/1323506-6ea944363fa48bac.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>可以看出一个集群NAS系统其实可以分为三层架构</p>
<ul>
<li><p>第一层：底层存储空间层，可以是Share Everything（共享型）或者Share Nothing（非共享型）</p>
</li>
<li><p>第二层：集群文件系统层，它建立在共享型或者非共享型存储空间之上</p>
<ul>
<li><p>如果底层存储是共享型的话，一般文件系统层都使用Single Filesystem Image。</p>
</li>
<li><p>如果底层存储使用非共享型，则既可使用Single Path Image ,又可使用Single Filesytem Image模式。</p>
</li>
</ul>
</li>
<li><p>第三层：NAS协议输出层，可以有四种访问模式：传统CIFS，传统NFS，pNFS并行客户端，并行或者串行访问。</p>
</li>
</ul>
<p>总结一下，将集群文件系统中的文件用NAS协议输出，就是<strong>集群NAS。</strong>它可以对外提供统一的命名空间，以及统一管理，若是出现了故障，还可以进行故障的切换，在线平稳的迁移等。</p>
<p>所以集群NAS不是简单的NAS设备的堆砌，它可以更加的灵活，比如</p>
<ul>
<li><p>集群NAS有统一命名空间</p>
<p>  比如某个应用程序需要在一个目录下放几十万个小文件，如果要把这么多文件放到传统的NAS的同一目录下，性能相当的低。</p>
<p>  如果我们把文件分散到不同的目录呢，虽然可以并发读取小文件，但是每个文件存放的路径必须对主机可见，麻烦的事就来了，我们必须得修改应用程序来适应这么多目录。</p>
<p>  此时集群NAS的统一命名空间就非常有用了，我们之前说过，统一命名空间指的是对外呈现统一的虚拟目录，屏蔽了底层的细节。具体做法是将文件系统承载于多个Segment，每个Segment又分配到不同的Segment Server上，这样主机只需要挂载一个目录，而且还不影响性能。</p>
</li>
<li><p>统一管理、故障切换、在线迁移。如果集群NAS设备之间共享存储则</p>
<ul>
<li><p>集群NAS可以随时将负载过高的节点上的Segment迁移到负载低的，因为这些Segment Server之间共享存储，所以不涉及到数据移动的过程。</p>
</li>
<li><p>独立的NAS  Server发生故障，所管理的数据就无法访问了，但是集群NAS因为共享存储，所以在某节点故障之后，可以由正常节点进行接管（后端Segment以及IP地址等），</p>
</li>
</ul>
</li>
</ul>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

        
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="en">
    <link itemprop="mainEntityOfPage" href="https://duyang2903.gitee.io/2017/11/15/%E5%A4%A7%E8%AF%9D%E5%AD%98%E5%82%A8%EF%BC%8C%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%882%E7%AB%A0%EF%BC%89%EF%BC%8C-SSD/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="dy2903">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="dy2903的博客">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          
            <a href="/2017/11/15/%E5%A4%A7%E8%AF%9D%E5%AD%98%E5%82%A8%EF%BC%8C%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%882%E7%AB%A0%EF%BC%89%EF%BC%8C-SSD/" class="post-title-link" itemprop="url">大话存储，学习笔记（2章），SSD</a>
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">Posted on</span>

              <time title="Created: 2017-11-15 00:00:00" itemprop="dateCreated datePublished" datetime="2017-11-15T00:00:00+08:00">2017-11-15</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">Edited on</span>
                <time title="Modified: 2019-11-15 11:21:59" itemprop="dateModified" datetime="2019-11-15T11:21:59+08:00">2019-11-15</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>我们知道机械硬盘最大的缺点在于，寻道时间比较长，也就是不适合随机小块IO。所以这几年固态存储大行其道，因为它对任何地址访问的开销都相等，节省了机械寻道时间，所以随机IO性能很好。</p>
<p>当前的SSD硬盘，单块SSD的大块连续读吞吐量超过了350MB/s，写超过了210MB/s，甚至4K块随机读吞吐量超过了200MB/s，写超过了180MB/s，随机读IOPS超过了600，随机IO延迟不超过1ms。这种速度满足当前主流的架构不成问题。</p>
<h1 id="SSD固态硬盘的硬件组成"><a href="#SSD固态硬盘的硬件组成" class="headerlink" title="SSD固态硬盘的硬件组成"></a>SSD固态硬盘的硬件组成</h1><blockquote>
<p>SSD(Solid State Drive)：是一种利用Flash芯片或者DRAM芯片作为数据永久存储的硬盘。所以不再使用磁技术来存储数据。</p>
</blockquote>
<ul>
<li><p>利用DRAM作为永久存储介质的SSD，又称为RAM-Disk，使用DRAM内存条来存储数据，所以在外部电池断开后，需要使用电池来维持DRAM中的数据。</p>
</li>
<li><p>基于Flash介质的SSD：使用“浮动门场效应晶体管”的晶体管来保存数据，每个这样的晶体管叫做一个“Cell”，即单元。有两种类型的单元：</p>
<ul>
<li><p>Single Level Cell(SLC)：每个单元可以保存1B的数据</p>
</li>
<li><p>Mult Level Cell(MLC)：每个单元可以保存2B的数据。所以MLC容量是SLC的两倍，成本却与SLC大致相当。但因为MLC的每个单元需要存储2B，所以复杂度比较高，出错率自然比较高。</p>
</li>
</ul>
</li>
</ul>
<h2 id="Flash-芯片"><a href="#Flash-芯片" class="headerlink" title="Flash 芯片"></a>Flash 芯片</h2><h3 id="Cell"><a href="#Cell" class="headerlink" title="Cell"></a>Cell</h3><p>本节我们介绍一下Cell的构成，这就是<strong>SSD可以在掉电后不丢失信息的原因</strong><br><img src="http://upload-images.jianshu.io/upload_images/1323506-b9ebb5155632d2b5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>SSD是由浮动门构成的，所谓<strong>浮动门</strong>是一个逻辑电路，四周被$SiO_2$包裹着。在Word Line（字线）上抬高电势，电子存储在浮动门中，字线恢复电势，电子不会丢失，也就是说浮动门仍然是充电的。</p>
<p><strong>那么什么时候状态为0，什么时候状态为1呢</strong>？充电到一定电势的后表示0，电势降到一定的阈值以后，表示为1。</p>
<p>在前面我们说过，MLC可以在一个Cell里面保存多位，也就是一个Cell可以有多种电势阈值，这样就可以表示00,01,11,10 4种状态。</p>
<h3 id="Cell串"><a href="#Cell串" class="headerlink" title="Cell串"></a>Cell串</h3><p>把多个Cell串联起来，就组成了<strong>Cell串</strong>。对每个cell串，每次只能读写其中一个Cell，所以我们会把多个Cell串并联起来，并行操作，这样就可以读多位数据呢。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-86ef5cc0e71ba221.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>NADD就是由这种晶体管有序排列起来的Flash芯片。每4314<em>8=34512个Cell组成一个Page，当然这只是逻辑上，它是IO的最小单位。每个Page可以存放*</em>4KB的内容**。</p>
<p>每128个Page组成一个Block，每2048个Block组成一个Plane区域。而一个Flash芯片由两个区域组称，一个存储奇数序号，另一个存储偶数序号。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-27356910307c5d4d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h2 id="SSD固态盘的构成"><a href="#SSD固态盘的构成" class="headerlink" title="SSD固态盘的构成"></a>SSD固态盘的构成</h2><p>上面我们讲解了NAND Flash芯片的主要构成部分，现在我们来看SSD固态盘的整体构成。</p>
<p>下图为Intel X-25M固态硬盘的拆机图。里面包含：</p>
<ul>
<li>10片NAND  Flash芯片</li>
<li>SSD控制器</li>
<li>RAM  Buffer</li>
</ul>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-645aa5d6903a16a7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>SSD控制器芯片负责向所有的NAND Flash芯片执行读写任务，同样也就通过指令的方式来运作，因为地址信息和数据信息都在这8位的总线上传送，加上总线位宽太窄，所以一个简单的寻址都需要多个时钟周期才能仅完成。</p>
<p>我们知道芯片容量越大，地址就会越长，寻址时间也就会越长，<strong>对小块随机IO，Flash会随着容量的增加而变得越来越低效。</strong></p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-6c958bb8ec1bd367.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h2 id="读写数据流程"><a href="#读写数据流程" class="headerlink" title="读写数据流程"></a>读写数据流程</h2><p>下面来看一下读写操作都需要做哪些工作？</p>
<h3 id="如何读数据"><a href="#如何读数据" class="headerlink" title="如何读数据"></a>如何读数据</h3><p>当需要读某个Page时，Flash控制器将这个Page的字线组电势置为0，可以将电势值解码成1或者0，放到SSD的RAM Buffer中。</p>
<p>从上述过程就可以看出<strong>SSD的最小IO单位为1个Page</strong></p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-7ecaaa6bc1da40df.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h3 id="如何写数据"><a href="#如何写数据" class="headerlink" title="如何写数据"></a>如何写数据</h3><p><strong>Flash芯片要求在修改一个Cell中的位之前，必须擦除这个Cell。</strong>其实这个擦除动作就是将一个<strong>Block</strong>一下全<strong>放电</strong>。也就是每次擦除只能一下擦除整个Block，将所有的Cell全置1。</p>
<p>这就是SSD的一个非常致命的缺点，它不能单独擦除某个Page或者Cell</p>
<p>擦除完毕以后，SSD会以Page为单位进行写入。<br><img src="http://upload-images.jianshu.io/upload_images/1323506-9684c0ca3ed8e9b1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h1 id="SSD的问题"><a href="#SSD的问题" class="headerlink" title="SSD的问题"></a>SSD的问题</h1><h2 id="SSD天然的缺陷"><a href="#SSD天然的缺陷" class="headerlink" title="SSD天然的缺陷"></a>SSD天然的缺陷</h2><p>Flash芯片在写入数据的时候有很多效率低下的地方，这是Flash芯片的通病</p>
<ul>
<li><p>擦除前需要将整个Block清掉（Erase before overwrite）</p>
<p>  上面我们讲到过如果要写入数据，必须先Erase整个Block，而不只是把一个Page或者Cell给清掉。相比于机械磁盘，多了擦除的这个步骤。</p>
</li>
</ul>
<p>特别是如果仅仅需要更改某个Page的内容，却需要擦除整个Block，性能浪费很严重。我们可以看看修改只修改某个Page的过程，</p>
<ul>
<li><p>在擦除之前，先将Block的数据读入RAM中，</p>
</li>
<li><p>然后擦除整个Block，</p>
</li>
<li><p>再更新RAM中的对应Page，写回Flash芯片中</p>
</li>
</ul>
<p><strong>这也是SSD的缓存通常比较大的原因。</strong></p>
<p>这就叫做写扩大，我们姑且称之为<strong>写惩罚</strong></p>
<p>这个时候我们会问， 为什么如果只需要修改一个Cell，却需要把Block放电？</p>
<p>因为Cell之间是存在干扰的，如果有的在充电，有的在放电，则会产生不可控的干扰问题。所以不如直接将所有的先放电。</p>
<p>那 为什么需要一次擦一个Block，而不是一个Page？</p>
<p>这是管理粒度的问题，粒度越小，管理开销越大，所以一次擦一个Block是一种比较折中的方案。</p>
<p>不过幸好，向Free Space写入数据时，因为里面没有被写过，所以不需要擦除，当然<strong>没有写惩罚</strong>。</p>
<p><strong>但是另一个问题又来了，SSD如何知道哪些是Free Space？</strong></p>
<p>我们知道只有文件系统才知道硬盘上哪些数据是有用的，它会使用元数据来进行记录，即使是删除一份数据也只是修改了元数据，而不是把数据真正的删除掉。</p>
<p>这样看来，SSD其实是不知道硬盘上哪些地方是所谓的Free Space，它只会把数据往从来没修过的地方写，所以Free Space会越来越少。</p>
<ul>
<li>Wear Off：</li>
</ul>
<p>什么是Wear off？就是逻辑门充放电次数过多，$SiO_2$绝缘层的绝缘能力遭到损耗，逐渐不再绝缘，无法保证有充足的电荷，也就是Cell已经物理损坏了。</p>
<p>更糟糕的是，损坏的Cell会拖累整个Page，因为最小的寻址单位是Page。这个Page的逻辑地址会被重定向到其他的Page上</p>
<p>MLC因为器件复杂，可擦写的寿命小于10000次，而SLC则十倍于MLC，小于100000次。<br><img src="http://upload-images.jianshu.io/upload_images/1323506-2cc75431eff51aab.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h2 id="如何解决？"><a href="#如何解决？" class="headerlink" title="如何解决？"></a>如何解决？</h2><p>之前我们提到SSD在写上有会极大的写惩罚，而且会加速Wear off，有什么好的解决方案？</p>
<ul>
<li><p>方法一：拆东墙补西墙重定向写</p>
<p>  如果同一个Cell被高频擦写，那么它被损坏的几率当然增大。如果一个Page之前都被写过了，我们不如把所有针对这个Page的写请求重定向到Free Space上.</p>
<p>  这样的好处在于对Free Space的写是不需要提前<strong>擦除</strong>的，减少了擦除次数。不过这些被写过的Page也不能浪费了，我们可以把他们标为”Garbage”，等待比较多的时候，再<strong>批量</strong>回收。</p>
<p>  这样做的目的是将写操作平衡到所有可能的Block中，降低单位时间内的每个Block擦写次数。问题是，Free Space会越来越少，重定向写的几率也会越来越少，最后降为0.</p>
<p>  而且因为有重定向，SSD内部很定需要维护一个<strong>地址映射表</strong>，需要SSD的CPU能维护一定比较复杂的程序，称为<code>wear Leveling</code>(损耗平衡算法)</p>
</li>
<li><p>方法二：定期清垃圾</p>
<p>  前面我们说过SSD自己是不知道哪些空间是Free Space，但是文件系统知道，可以在操作系统里面运行一种Wiper，可以不断扫描，然后把空闲空间通知给SSD，由SSD来执行擦除工作。</p>
<p>  不过这种清除工作只能定期执行</p>
</li>
<li><p>方法三：持续清除体内垃圾</p>
<p>  有没有办法可以让文件系统在删除之后实时通知SSD。</p>
<p>  可以使用ATA指令里面一个功能——TRIM，现在已经集成在很多SSD的Firmware中了。</p>
</li>
<li><p>方法四：IO 优化</p>
<p>  之前的方法主要着力点在Free Space。我们也可以采用另一种思路，对IO进行优化。<br>  比如<strong>Delay write</strong>。现在有两个针对同一个地址的写IO，在Write1还没写到硬盘之前，Write 2就到了，控制器直接用Write 2来覆盖Write 1 ，这个操作是在<strong>内存里面</strong>的，省去了Write 1 写入硬盘的过程。这种机制为“写命中”的一种情况。</p>
<p>  问题就是数据可能不一致。比如有如下IO：Write 1 , Read 2 , Write 3 ，此时如果用Write 3取代Write 1，那么Read 2 读出了Write 3 的内容，实际上Read 2应该读Write 1的内容，所以数据不一致。</p>
<p>  另外还可以使用<strong>Combine Write</strong>，对机械硬盘来说，如果控制器一段时间内收到多个写IO，而这些写IO的地址在逻辑上是连续的，可以将小写IO合并为大IO，一次性写入，节约了SCSI指令周期。<br>  对SSD来说，逻辑地址和物理地址存在一个映射关系，我们读数据的时候是根据这个映射关系来的，所以可以任何地址的小IO整合为大IO，直接写到Free的Block中。</p>
<p>  因为SSD需要对数据进行合并以及优化，所以SSD对收到的写数据一般采用Write Back模式，即收到主机控制器的数据立即返回成功，然后异步处理。这样就存在一个风险，如果掉电了，数据就会丢失，所以SSD是需要掉电保护机制的，一般使用一个超级电容来维持掉电之后的脏数据刷盘。</p>
</li>
<li><p>预留备用空间</p>
<p>  为了防止文件系统将数据写满的极端情况，SSD可以自己预留一部分备用空间用于重定向写，因为不通知文件系统，所以只有SSD才知道，这样就有了一个永远不会被占用的定额Free Space。</p>
</li>
</ul>
<p>下面说一个题外话， 为什么不需要对SSD进行碎片整理？</p>
<p>我们来看一下机械硬盘为什么需要进行碎片整理？机械硬盘主要瓶颈在于寻道时间，因为碎片是不零散的块，寻道次数会很多。整合到一起呢，逻辑上连续的LBA地址同样也是物理上连续的，磁盘臂换道的时间就少了。</p>
<p>但是对SSD而言，没有了磁盘臂，它是通过映射关系来读的，即使整理了碎片也没啥用。反而做了大堆无用功，还会减少SSD的寿命。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-c9e97f42277d8bb9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h2 id="SSD如何处理Cell损坏"><a href="#SSD如何处理Cell损坏" class="headerlink" title="SSD如何处理Cell损坏"></a>SSD如何处理Cell损坏</h2><p>机械硬盘如果损坏，则该扇区不能磁化，磁头会感知。</p>
<p>而Flash中的Cell被击穿一定次数后，损坏的几率很高，</p>
<p>SSD如何判断损坏的呢？实际上Cell只有充电和没充电两种状态，那么电路实际上无法直接判断是漏电导致的还是说原本就是没电的。</p>
<p><strong>只好使用ECC纠错码</strong>，每次读出某个Page需要进行ECC校验。Flash厂商会在Datasheet中给出最低要求，即使用该颗粒起码配合使用何种力度的纠错码。比如8b@512B，意味着512B的范围内出现8b错误，可以纠错。如果超过了，就只能上报“不可恢复错误”。</p>
<p><strong>厂商给出的纠错码力度越低，说明颗粒的品质越好，损坏率越低。</strong></p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-251fff33dddee99c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h2 id="SSD的前景"><a href="#SSD的前景" class="headerlink" title="SSD的前景"></a>SSD的前景</h2><p>以上缓解SSD效率的问题都是治标不治本的，为了解决多个问题，设计了若干的补救措施，需要TRIM来维持，而且数据不能占得太满。SSD在使用的时候也略显尴尬，因为成本太高，用户若需要一个10TB的存储系统，不可能都用SSD，所以很多厂商出品了SSD + HDD混合存储，其实就是将Flash芯片作为磁盘的二级缓存，一级缓存是RAM，二级是FLASH，三级是磁盘片。</p>
<p>有人说传统磁盘有64MB的RAM缓存，为什么还需要Flash作为下一级的缓存？如果只用磁盘的RAM，首先空间比较小，很快就塞满了，另外不能掉电，刷到盘片里面的时候，会导致性能骤降。</p>
<p>而使用Flash芯片再加一级缓存，可以把RAM中的数据存储Flash中，最关键的是可以掉电，这样可以直接回复给控制器成功之后，磁盘驱动器再在后台将数据从Flash中写到磁盘片中，这样既比纯SSD便宜，还保证了性能。</p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

        
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="en">
    <link itemprop="mainEntityOfPage" href="https://duyang2903.gitee.io/2017/11/14/%E5%A4%A7%E8%AF%9D%E5%AD%98%E5%82%A8%EF%BC%8C%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%881,2,3%E7%AB%A0%EF%BC%89%EF%BC%8C%E7%A3%81%E7%9B%98/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="dy2903">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="dy2903的博客">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          
            <a href="/2017/11/14/%E5%A4%A7%E8%AF%9D%E5%AD%98%E5%82%A8%EF%BC%8C%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%881,2,3%E7%AB%A0%EF%BC%89%EF%BC%8C%E7%A3%81%E7%9B%98/" class="post-title-link" itemprop="url">大话存储，学习笔记（1,2,3章），磁盘.md</a>
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">Posted on</span>

              <time title="Created: 2017-11-14 00:00:00" itemprop="dateCreated datePublished" datetime="2017-11-14T00:00:00+08:00">2017-11-14</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">Edited on</span>
                <time title="Modified: 2019-11-15 11:11:45" itemprop="dateModified" datetime="2019-11-15T11:11:45+08:00">2019-11-15</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>本文为《大话存储》的读书笔记。</p>
<h1 id="计算机的IO世界"><a href="#计算机的IO世界" class="headerlink" title="计算机的IO世界"></a>计算机的IO世界</h1><h2 id="总线"><a href="#总线" class="headerlink" title="总线"></a>总线</h2><h3 id="总线的概念"><a href="#总线的概念" class="headerlink" title="总线的概念"></a>总线的概念</h3><blockquote>
<p>计算机中所有的IO都通过共享总线的方式来实现。</p>
</blockquote>
<p>总线实际上就是一条或多条的物理导线。密密麻麻的印到电路板上，而且为了避免高频振荡的干扰，一般都会分组印刷到不同的电路板上，然后压合起来。</p>
<h3 id="总线的分类"><a href="#总线的分类" class="headerlink" title="总线的分类"></a>总线的分类</h3><p><img src="http://upload-images.jianshu.io/upload_images/1323506-ea0b4a369a2b24e1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<blockquote>
<p><strong>PCI总线</strong>是目前x86服务器普遍使用的<strong>南桥与外设</strong>连接的总线技术。</p>
</blockquote>
<p>PCI总线的<strong>地址总线和数据总线</strong>是分时复用的，这样可以节省管脚数量。</p>
<p>在数据传输时，PCI协议上有三种不同的角色</p>
<ul>
<li>主，也就是发起者</li>
<li>从，Target或者Slave</li>
<li>仲裁者Arbiter</li>
</ul>
<h2 id="CPU、内存、磁盘交互过程"><a href="#CPU、内存、磁盘交互过程" class="headerlink" title="CPU、内存、磁盘交互过程"></a>CPU、内存、磁盘交互过程</h2><p>下面我们来介绍一下<strong>CPU、内存、磁盘交互过程</strong></p>
<p>CPU、内存、磁盘通过总线相互连接，所以通路的因素具备了。</p>
<p>然后需要上通路上的设备有不同的标识，这样才可以区分开。<strong>所以每个IO设备在启动的时候，都需要向物理机的内存中映射一个地址。</strong></p>
<p>接下来是<strong>发</strong>的过程。</p>
<p>CPU首先将IO地址放到系统总线上，接下来传三条指令</p>
<ul>
<li>是想读还是想写，是否开磁盘缓存等。</li>
<li>从哪儿读：磁盘的LBA地址</li>
<li>读到地址放到内存那里？<br>通过总线传到磁盘控制器上。</li>
</ul>
<p>接着<code>磁盘控制器</code>主要做：</p>
<ul>
<li>查找并寻道</li>
<li>通过<code>DMA</code>技术，也就是磁盘控制器可以直接对<strong>内存</strong>寻址并进行写操作。（这样可以解放CPU）</li>
</ul>
<blockquote>
<p>上述所说的过程均为CPU对磁盘发送某种指令的信息，<strong>告诉磁盘控制器应该怎么操作</strong>。而这一类的指令可以分为SCSI指令集和ATA指令集。SCSI指令集更高效。</p>
</blockquote>
<p>所以所谓<code>SCSI指令集</code>其实就是CPU告诉磁盘控制器到底是想读还是想写，从磁盘的那个位置开始，有多长等关键信息的规范</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-f740f94cc0533c91.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h1 id="磁盘原理"><a href="#磁盘原理" class="headerlink" title="磁盘原理"></a>磁盘原理</h1><p>本章所提到的磁盘主要指的是机械磁盘。</p>
<p>要了解磁盘主要需要通过如下几个方面；</p>
<ul>
<li>磁盘的结构</li>
<li>数据的组织方式</li>
<li>高层技术：队列、无序存储、磁盘缓存</li>
<li>磁盘接口技术</li>
<li>磁盘驱动程序</li>
</ul>
<h2 id="为什么需要磁盘"><a href="#为什么需要磁盘" class="headerlink" title="为什么需要磁盘"></a>为什么需要磁盘</h2><p>CPU的速度比内存块100倍，比硬盘快100万倍，也就是说磁盘速度是相当的慢的，有人说整个系统的速度就是被磁盘拖慢的。确实如此，但是为什么还需要磁盘呢？</p>
<p>内存的速度虽然快，但是<strong>断电</strong>了怎么办，而且硬盘是以TB甚至TB计算的，内存如果达到这么大的容量，价格将不可想象。</p>
<p>我们可以憧憬一下，人类如果造出一个能断电存储、容量还得大、访问速度快最关键的要<strong>便宜</strong>的硬盘来，CPU就可以直接访问硬盘了。但是在这之间，我们还是必须容忍<strong>CPU-内存-硬盘</strong>速度不匹配的问题，这才引出了诸多的解决方案，比如用<strong>缓存、DMA、多线程等</strong></p>
<h2 id="磁盘的结构"><a href="#磁盘的结构" class="headerlink" title="磁盘的结构"></a>磁盘的结构</h2><p><img src="http://upload-images.jianshu.io/upload_images/1323506-376d2c76486d6ff2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>磁盘主要由盘片、磁头、步进电机构成</p>
<ul>
<li>硬盘一般是多个盘片固定在一个公共的<strong>转轴</strong>上</li>
<li>主轴电机带动盘片组高速旋转产生<strong>高速气流</strong>，将磁头浮起；</li>
<li>磁头组在电机的带动下作<strong>径向运动</strong></li>
</ul>
<p>通俗的说来，盘片上布满磁性介质，类似于一张<strong>白纸</strong>，如果想在上面记录的话，一般需要划<strong>格子</strong>，格子就是所谓的磁道。</p>
<p><strong>因为盘片是圆的，所以就每个同心圆（磁道）就是类似于稿纸的一行，每一行上再分为若干的格子（扇区）</strong>，磁头就类似于打印喷头</p>
<p>对于打印机来说，需要纸不断的移动，但是这样效率太低了，对于磁盘来说可以让磁盘不断的旋转，然后移动磁头来进行换行。</p>
<blockquote>
<p>目前服务器中一般选择1万转/s，可以获得比较高的性价比。</p>
</blockquote>
<ul>
<li>磁道：同心圆</li>
<li>扇区：每个同心圆的上每段<strong>圆弧</strong>，是读写的<strong>最小单位</strong></li>
<li>柱面：<strong>所有盘面上的同一磁道</strong>，在竖直方向上构成一个<strong>圆柱。</strong></li>
<li>每个盘片上都有可以读写数据的<strong>磁头</strong>。</li>
</ul>
<blockquote>
<p><strong>需要注意</strong>的是，数据的读写是按照<strong>柱面</strong>来进行的，也就是说首先在同一柱面的内从0磁头开始，依次向下在同一柱面的不同盘面上进行操作。为什么会这样呢？因为这样操作只需要改变<strong>电流</strong>，只需要通过电子切换，而不需要改变磁道（机械切换），速度更快。</p>
</blockquote>
<p>我们需要记住一个<code>规律</code>：把磁头挪到指定的<strong>磁道</strong>的速度是非常慢的。</p>
<h2 id="扇区寻址"><a href="#扇区寻址" class="headerlink" title="扇区寻址"></a>扇区寻址</h2><p>了解了磁盘结构以后，我们来看一下磁盘如何寻址。</p>
<p>我们可以把寻找磁盘里面的数据想象成在一个<strong>小区</strong>里面找某一户人家一样。我们需要知道三个信息：在哪一栋、哪一层、哪一户，然后就可以找到他了。同样，找磁盘上的数据可以通过<strong>柱面（哪一栋）、磁头（哪一层）、扇区（哪一户）</strong>找到某个数据。</p>
<p>但是这种编码方式比较的麻烦，不利于程序的编写。就比如一户人家在12栋3楼4号，并不直观。那么我们可以用一个<strong>线性地址</strong><code>120304</code>来表示这户人家的地址，显然这种方法更利于编程。</p>
<p>所以我们可以将<strong>磁道磁头扇区与另一种线性地址对应</strong>起来，这种对应关系保存在磁盘控制电路的ROM里面，可以在磁盘初始化的时候载入缓存以便查询。</p>
<blockquote>
<p>于是磁盘可以对外提供<strong>线性地址</strong>，即LBA（Logical block address）地址。可以将磁盘想象成只有一个磁道，是无限长的直线，扇区为上面的等长的线段，这样可以屏蔽柱面、磁头等比较复杂的东西，对外而言寻址方式更为简便。</p>
</blockquote>
<blockquote>
<p>也就是说通过磁盘控制器可以对外屏蔽查找具体扇区的细节，进行逻辑的抽象，这样就完成了物理地址到逻辑地址的抽象、虚拟、映射</p>
</blockquote>
<h2 id="磁盘高层技术"><a href="#磁盘高层技术" class="headerlink" title="磁盘高层技术"></a>磁盘高层技术</h2><p>我们在前面的介绍中说过，磁盘进行磁道的切换最费时间，所以我们会通过多种方法来避免频繁的磁道切换。如下就是比较常用的解决方案。</p>
<h3 id="队列技术"><a href="#队列技术" class="headerlink" title="队列技术"></a>队列技术</h3><p>第一个指令向让读最外圈的数据，第二个指令向读最内圈的数据，第三个指令又向读最外圈的数据，如果按照这个顺序来，需要频繁的换道，我们知道换道时间非常长，是性能的瓶颈。</p>
<p>所以可以先切换到最外圈，执行完第一个指令，然后先执行第三个指令，最后再执行第二个指令，类似于电梯，<strong>每次把同方向的人都搭载上去。</strong></p>
<h3 id="无序传输技术"><a href="#无序传输技术" class="headerlink" title="无序传输技术"></a>无序传输技术</h3><p>要求读某些扇区的内容，如果不做优化的话，肯定直接傻乎乎的从开头开始读。但是实际上，有可能磁头离数据段的末尾近啊。</p>
<p>那么我们完全可以无视读出数据的顺序，从<strong>离磁头近</strong>的扇区开始读。</p>
<h3 id="磁盘缓存"><a href="#磁盘缓存" class="headerlink" title="磁盘缓存"></a>磁盘缓存</h3><p>磁盘的速度是相当慢的，所以与外界的内存、CPU的访问有极大的矛盾。就好比一个团队里面，有人做事快，有人做事慢，做事快的就会等做事慢的。</p>
<p>当然这种矛盾是无法调和的，那有什么折中的方法吗？有，有句话叫<code>笨鸟先飞</code>，所谓缓存就是笨鸟先飞。</p>
<p>比如说做事慢的人，虽然手脚不麻利，但是有个好处，记忆力好，而且勤奋。所以当事来了以后，他虽然没办法立刻给答复，但他可以先记住啊，然后告诉做事快的人先去忙。同样，他也可以提前把一些事先做了，然后准备着。避免手忙脚乱。</p>
<p>回到磁盘上，<code>缓存</code>其实就是一块电路板上的RAM芯片，他的速度就很快，而且如果断电的话，里面的数据会丢失。</p>
<p><strong>缓存</strong>的主要的作用是：</p>
<ul>
<li>接收指令和数据</li>
<li>进行预读</li>
</ul>
<p>有些资料说禁用磁盘缓存，这种说法容易造成误解。</p>
<p>实际上禁用磁盘缓存就是Write Through（直通）模式，也就是说磁盘收到指令和数据并需要进行写入的时候，不是在数据到达缓存的时候就返回成功，而是<strong>应该等到数据都落入盘片以后</strong>，才向<code>控制器</code>返回成功信号。<strong>相当于禁用了缓存</strong></p>
<p>实际上这种模式，数据还是会到达缓存。<br>SCSI指令中有两个参数可以控制缓存：</p>
<ul>
<li>DPO(Disable PageOut)：禁止缓存中的数据页被换出，置了这个位的数据不能将其他数据换出。</li>
<li>FUA：Force Unit Access：强制盘片访问，也就是Write Through</li>
</ul>
<p>所以如果DPO和FUA都置1了， 相当于完全不使用缓存的提速作用。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-f3cc8cefb6058c71.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h3 id="影响磁盘性能的因素"><a href="#影响磁盘性能的因素" class="headerlink" title="影响磁盘性能的因素"></a>影响磁盘性能的因素</h3><ul>
<li>转速：主要影响连续IO的吞吐量。因为转得越快，数据传输时间越短。</li>
<li>寻道速度：主要影响<strong>随机IO</strong>。因为随机IO下，必须频繁的换道。</li>
<li>单碟容量：单碟容量越高，单位空间内的数据量越大</li>
<li>接口速度：最不重要，因为目前的接口速度已经满足了磁盘能达道的最高传输带宽。</li>
</ul>
<h2 id="磁盘接口技术"><a href="#磁盘接口技术" class="headerlink" title="磁盘接口技术"></a>磁盘接口技术</h2><p>不管硬盘内部多么复杂，一定需要向使用者提供接口，以屏蔽访问的细节，这个接口不是物理的接口，而是硬盘面向外部的时候，为了被方便的使用，<strong>所提供的抽象的协议。</strong></p>
<p>目前硬盘提供的物理接口</p>
<ul>
<li>用于ATA指令的IDE接口</li>
<li>用于ATA指令的SATA接口</li>
<li>用于SCSI指令的并行SCSI接口</li>
<li>用于SCSI指令的串行SCSI（SAS）接口</li>
<li>用于SCSI指令系统，并且承载于FC协议的串行FC接口</li>
</ul>
<p>列成表格如下</p>
<table>
<thead>
<tr>
<th>接口</th>
<th>英文</th>
<th>指令系统</th>
<th>备注</th>
</tr>
</thead>
<tbody><tr>
<td>IDE接口</td>
<td>Parallel ATA(Advanced Technology Attachment)</td>
<td>ATA指令系统</td>
<td>Integrated Drive Electronics</td>
</tr>
<tr>
<td>SATA接口</td>
<td>Serial ATA</td>
<td>ATA指令系统</td>
<td></td>
</tr>
<tr>
<td>并行SCSI接口</td>
<td>Parallel SCSI(small computer system interface)</td>
<td>SCSI指令系统</td>
<td></td>
</tr>
<tr>
<td>SAS接口</td>
<td>serial SCSI</td>
<td>SCSI指令系统</td>
<td></td>
</tr>
<tr>
<td>FC接口</td>
<td>Fibre Channel</td>
<td>SCSI指令系统</td>
<td>承载FC协议的串行SCSI接口</td>
</tr>
</tbody></table>
<h3 id="IDE硬盘接口"><a href="#IDE硬盘接口" class="headerlink" title="IDE硬盘接口"></a>IDE硬盘接口</h3><p>IDE，integrated Drive Electronics ，电子集成驱动器，本意是把控制电路、盘片、磁头放到一个容器中的硬盘驱动器，制造比较容易。</p>
<p>IDE接口，也称PATA接口，也即并行ATA</p>
<blockquote>
<p>ATA协议需要主机更多参与IO，无法支持大量的并发访问，适用于家用电脑和低端服务器；</p>
</blockquote>
<h3 id="SATA硬盘接口"><a href="#SATA硬盘接口" class="headerlink" title="SATA硬盘接口"></a>SATA硬盘接口</h3><blockquote>
<p>SATA：串性ATA，用串行线路传输数据，但是指令集仍然是ATA。</p>
</blockquote>
<p>下图是IDE与SATA线缆的对比</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-2592dd049a78594f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>SATA的优点是：</p>
<ul>
<li>可以对指令及数据包进行CRC，而PATA只能对来回传输的数据进行较验。</li>
<li>相对于IDE的80芯更<strong>节省空间。</strong></li>
</ul>
<p>目前SATA规范中接口速率为6Gb/s，有于SATA使用8bit/10bit编码，所以6Gb/s相当于600MB/s的接口速率，但是实际上性能没有得到多大的提升。</p>
<p>因为硬盘的速率瓶颈在于硬盘内部的寻道，而非传输，<strong>接口速率的提高最直接影响从缓存中的读写。</strong></p>
<h3 id="SCSI硬盘接口"><a href="#SCSI硬盘接口" class="headerlink" title="SCSI硬盘接口"></a>SCSI硬盘接口</h3><p>SCSI接口更为<strong>灵活</strong>，而且<strong>性能</strong>也较高。</p>
<p>可以有8个或者16个SCSI设备连接在SCSI通道上，缺点是比较贵。因为一般需要配备价格不菲的<strong>SCSI卡</strong>，而且SCSI接口的设备在安装、设置时比较麻烦。</p>
<p>SCSI总线连接图：<br><img src="http://upload-images.jianshu.io/upload_images/1323506-2ecaa66752ba6eaa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>一条总线上最多16个节点，各分配一个SCSI ID <strong>，其中SCSI控制器需要占一个ID</strong></p>
<p><strong>SCSI卡上有一块类似CPU的芯片可以对SCSI设备进行控制，减少了CPU的负担，所以适合大量并发访问场景，适用于企业级数据中心</strong></p>
<p>SCSI卡将SCSI总线上的设备，经过PCI总线传递给内存中运行的SCSI卡的<code>驱动程序</code>，<strong>让OS知道所有设备。</strong></p>
<p>下图是SCSI总线与计算机总线的连接图</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-5aa0c0d273157104.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<p>可以看出SCSI卡一端接主机的PCI，一端用SCSI控制器接入SCSI总线。</p>
<blockquote>
<p>多通道SCSI卡：如果一张卡上有多个控制器，每个控制器独立掌管一条总线</p>
</blockquote>
<p>多通道SCSI控制器卡示意图<br><img src="http://upload-images.jianshu.io/upload_images/1323506-46923668dadc9ed0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h4 id="SCSI协议寻址方式"><a href="#SCSI协议寻址方式" class="headerlink" title="SCSI协议寻址方式"></a>SCSI协议寻址方式</h4><p>SCSI协议的寻址方式按照<strong>“控制器——通道——SCSI ID —— LUN ID (logic unit number) ”。</strong></p>
<p>一个主机IO总线上可以有多个控制器，每个控制器可以有多条后端的SCSI总线（通道），每个SCSI总线上挂着8个或者16个SCSI设备，通过SCSI ID来区分。</p>
<p>然而SCSI ID不是最后一层地址，还有一个LUN ID 。 SCSI设备不能物理上再分割了，所以只能在逻辑上分，每个SCSI ID下面可以区分出若干的LUN ID 。这样一条SCSI总线上可接入的逻辑存储单元数量大大增加。</p>
<p>LUN对于传统的SCSI总线意义不大，但是对带RAID功能的SCSI接口磁盘阵列来说，因为会产生很多虚拟磁盘，所以可以使用LUN来扩充可寻址范围。习惯上称磁盘阵列生成的虚拟磁盘为LUN。</p>
<blockquote>
<p>SCSI控制器也是总线上的一个节点，不过优先级必须是最高的。</p>
</blockquote>
<h2 id="磁盘控制器、驱动器控制器电路、磁盘控制器驱动程序的区别"><a href="#磁盘控制器、驱动器控制器电路、磁盘控制器驱动程序的区别" class="headerlink" title="磁盘控制器、驱动器控制器电路、磁盘控制器驱动程序的区别"></a>磁盘控制器、驱动器控制器电路、磁盘控制器驱动程序的区别</h2><h3 id="磁盘控制器"><a href="#磁盘控制器" class="headerlink" title="磁盘控制器"></a>磁盘控制器</h3><p>硬盘的接口：</p>
<ul>
<li>物理接口：硬盘接入磁盘控制器需要的接口</li>
<li>逻辑接口：指令系统，指令集定义了“怎么样向磁盘发送数据和读数据”，这套指令集是由专门的芯片来生成，这就是<code>磁盘控制器</code></li>
</ul>
<blockquote>
<p>磁盘控制器的作用：参与底层总线的初始化、仲裁过程，向驱动程序提供简单的接口。</p>
</blockquote>
<p>所以<code>驱动程序</code>只需要将要读写的<strong>设备号、读写的初始地址、长度</strong>告诉控制器即可，其他的由控制器来完成</p>
<h3 id="驱动器控制器电路"><a href="#驱动器控制器电路" class="headerlink" title="驱动器控制器电路"></a>驱动器控制器电路</h3><ul>
<li>驱动器控制电路：位于磁盘的<strong>驱动器</strong>上，负责驱动磁头臂来读写数据</li>
<li>磁盘控制器：向磁盘驱动器的控制器电路发送指令。</li>
</ul>
<p>所以流程是，CPU通过总线发送指令给主板上的磁盘控制器，<br>磁盘控制器通过线缆发送指令给驱动器<br>驱动器控制磁盘进行读写。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-0876fb7ee646aa80.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<blockquote>
<p>CPU操作磁盘控制器的指令系统叫磁盘控制器<code>驱动程序</code><br>控制器收到指令通过电路逻辑运算生成的指令就是常说的<code>ATA指令集或者SCSI指令集。</code></p>
</blockquote>
<h3 id="为什么在SCSI磁盘上安装操作系统需要手动加载SCSI驱动？"><a href="#为什么在SCSI磁盘上安装操作系统需要手动加载SCSI驱动？" class="headerlink" title="为什么在SCSI磁盘上安装操作系统需要手动加载SCSI驱动？"></a>为什么在SCSI磁盘上安装操作系统需要手动加载SCSI驱动？</h3><p>机器刚通电，OS还没启动起来，<strong>所以也没加载磁盘控制器驱动，如何访问磁盘的呢？</strong></p>
<p>这要从机器启动的流程说起，系统的BIOS中存放了初始化系统的基本代码，所以机器启动后执行系统BIOS里面的代码，里面有一步就是去查找<strong>磁盘控制器上的BIOS地址</strong>，然后去这个地方再执行其中的代码以初始化控制器。</p>
<p>最后此BIOS让CPU提取0磁道中的第1扇区的代码，从而加载OS。</p>
<p>从上面的流程可以看出，系统BIOS会指示CPU查找<strong>磁盘控制器的BIOS地址</strong>，里面有最基本的磁盘控制器驱动程序。但是因为不完善，所以在OS内核启动的过程中，会用自己的驱动来接管。</p>
<p><strong>那么向SCSI磁盘上安装OS，必须手动加载SCSI驱动就原因就不难解释了。</strong></p>
<p>因为CPU必须通过执行驱动程序才能向磁盘驱动器发指令，而磁盘控制器BIOS里面的代码非常简单，功能很有限，只能适用于启动OS这种临时任务。所以必须加载完整功能的驱动程序。</p>
<p>对于ATA磁盘来说，ATA已经是非常成熟的技术了，控制器一般都是Intel的，所以操作系统安装程序在初始化执行的时候已经自行加载了驱动。</p>
<p>而SCSI磁盘的生产厂商很多，所以必须手动加载。</p>
<p>安装了OS的系统，启动之初从磁盘BIOS（ROM）中读取驱动程序，此时的执行速度很慢，但是一旦将OS本身的驱动程序读到了内存中以后，速度就可以增加。由于操作系统安装以后，就具有磁盘的驱动程序了，所以不需要每次手动加载。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-2e37a9bb6aff2879.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>
<h2 id="磁盘IOPS和吞吐量"><a href="#磁盘IOPS和吞吐量" class="headerlink" title="磁盘IOPS和吞吐量"></a>磁盘IOPS和吞吐量</h2><p>衡量磁盘的性能最重要的两个参数就是IOPS和吞吐量。</p>
<p>IOPS关注的就是每秒进行多少次的IO，跟随机读写的快慢有关。<br>而吞吐量关注的是硬盘在传输数据的时候数据流的速度。</p>
<h3 id="IOPS"><a href="#IOPS" class="headerlink" title="IOPS"></a>IOPS</h3><blockquote>
<p>IOPS：也就是每秒能进行多少次IO。这个值也不是固定的。</p>
</blockquote>
<p>写入10000个大小为1KB的文件，比写入一个10MB的文件耗费更多的时间。</p>
<p>因为10000个文件需要做好几万次IO，而写入10MB的大文件，因为是连续存放，所以只需要几十个IO。<br>对于写入10000个小文件，因为每秒需要的IO非常高，如果用具有较高IOPS的磁盘，将提速不少。写入10MB文件，就算用了较高的IOPS也不会提升速度。因为只需要少量的IO。只有用较大传输带宽的才会体现优势。</p>
<h2 id="传输带宽"><a href="#传输带宽" class="headerlink" title="传输带宽"></a>传输带宽</h2><blockquote>
<p>传输带宽：硬盘在传输数据时的数据流的速度。</p>
</blockquote>
<p>在同一块硬盘写入不同大小的数据，带宽不同。</p>
<p>硬盘的带宽如果高，在传输大块的连续的数据时有优势。</p>
<p>而具有高IOPS的硬盘在传输小块的不连续的数据具有优势。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1323506-2f7edafdb3180f95.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

  </div>

  
  <nav class="pagination">
    <a class="extend prev" rel="prev" href="/"><i class="fa fa-angle-left" aria-label="Previous page"></i></a><a class="page-number" href="/">1</a><span class="page-number current">2</span>
  </nav>



          </div>
          

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          Table of Contents
        </li>
        <li class="sidebar-nav-overview">
          Overview
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">dy2903</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">20</span>
          <span class="site-state-item-name">posts</span>
        </a>
      </div>
      <div class="site-state-item site-state-tags">
        <span class="site-state-item-count">2</span>
        <span class="site-state-item-name">tags</span>
      </div>
  </nav>
</div>
  <div class="feed-link motion-element">
    <a href="/atom.xml" rel="alternate">
      <i class="fa fa-rss"></i>RSS
    </a>
  </div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2019</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">dy2903</span>
</div>
  <div class="powered-by">Powered by <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> v4.0.0
  </div>
  <span class="post-meta-divider">|</span>
  <div class="theme-info">Theme – <a href="https://pisces.theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Pisces</a> v7.5.0
  </div>

        












        
      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>
<script src="/js/utils.js"></script><script src="/js/motion.js"></script>
<script src="/js/schemes/pisces.js"></script>
<script src="/js/next-boot.js"></script>



  
















  

  

</body>
</html>
